/*- * ============LICENSE_START======================================================= * SDC * ================================================================================ * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============LICENSE_END========================================================= */ package org.openecomp.sdc.be.components.validation; import com.google.gson.Gson; import fj.data.Either; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus; import org.openecomp.sdc.be.datatypes.elements.ToscaGetFunctionDataDefinition; import org.openecomp.sdc.be.datatypes.enums.ConstraintType; import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; import org.openecomp.sdc.be.datatypes.enums.PropertyFilterTargetType; import org.openecomp.sdc.be.datatypes.enums.PropertySource; import org.openecomp.sdc.be.impl.ComponentsUtils; import org.openecomp.sdc.be.model.CapabilityDefinition; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.ComponentInstance; import org.openecomp.sdc.be.model.ComponentInstanceInput; import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.model.InputDefinition; import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.ToscaPropertyData; import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache; import org.openecomp.sdc.be.model.dto.FilterConstraintDto; import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; import org.openecomp.sdc.be.model.tosca.validators.DataTypeValidatorConverter; import org.openecomp.sdc.be.model.validation.FilterConstraintValidator; import org.openecomp.sdc.exception.ResponseFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @org.springframework.stereotype.Component("NodeFilterValidator") public class NodeFilterValidator { private static final Logger LOGGER = LoggerFactory.getLogger(NodeFilterValidator.class); private static final String SOURCE = "Source"; private static final String TARGET = "Target"; private static final String INPUT_NOT_FOUND_LOG = "Input '{}' not found in parent component '{}', unique id '{}'"; private static final Set TYPES_WITH_SCHEMA = Set.of(ToscaPropertyType.MAP.getType(), ToscaPropertyType.LIST.getType()); private static final Set COMPARABLE_TYPES = Set.of( ToscaPropertyType.SCALAR_UNIT_SIZE.getType(), ToscaPropertyType.SCALAR_UNIT_TIME.getType(), ToscaPropertyType.SCALAR_UNIT_BITRATE.getType(), ToscaPropertyType.SCALAR_UNIT_FREQUENCY.getType(), ToscaPropertyType.BOOLEAN.getType(), ToscaPropertyType.STRING.getType(), ToscaPropertyType.INTEGER.getType(), ToscaPropertyType.FLOAT.getType()); private final ComponentsUtils componentsUtils; private final ApplicationDataTypeCache applicationDataTypeCache; private final FilterConstraintValidator filterConstraintValidator; @Autowired public NodeFilterValidator(final ComponentsUtils componentsUtils, final ApplicationDataTypeCache applicationDataTypeCache, final FilterConstraintValidator filterConstraintValidator) { this.componentsUtils = componentsUtils; this.applicationDataTypeCache = applicationDataTypeCache; this.filterConstraintValidator = filterConstraintValidator; } private static List getSelfPropertyFromGetFunction(final Component component, final ToscaGetFunctionDataDefinition toscaGetFunction) { switch (toscaGetFunction.getFunctionType()) { case GET_INPUT: if (component.getInputs() != null) { return component.getInputs(); } break; case GET_PROPERTY: if (component.getProperties() != null) { return component.getProperties(); } break; case GET_ATTRIBUTE: if (component.getAttributes() != null) { return component.getAttributes(); } break; } return List.of(); } public Either validateComponentInstanceExist(final Component component, final String componentInstanceId) { if (component == null || StringUtils.isEmpty(componentInstanceId)) { LOGGER.error("Expecting a component and a component instance id, given was '{}' and '{}'", component, componentInstanceId); final String componentName = component == null ? "?" : component.getName(); return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND, componentName, componentInstanceId)); } if (CollectionUtils.isEmpty(component.getComponentInstances()) || component.getComponentInstances().stream() .noneMatch(ci -> ci.getUniqueId().equals(componentInstanceId))) { LOGGER.error("Component '{}' node instance list is empty or component instance '{}' not found", component.getUniqueId(), componentInstanceId); return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND, component.getName(), componentInstanceId)); } return Either.left(Boolean.TRUE); } public Either validateFilter(final Component parentComponent, final String componentInstanceId, final List filterConstraint) { if (CollectionUtils.isEmpty(filterConstraint)) { return Either.left(true); } for (final FilterConstraintDto filterConstraintDto : filterConstraint) { final Either validationEither = validateFilter(parentComponent, componentInstanceId, filterConstraintDto); if (validationEither.isRight()) { return validationEither; } } return Either.left(true); } public Either validateFilter(final Component parentComponent, final String componentInstanceId, final FilterConstraintDto filterConstraint) { validateFilterConstraint(filterConstraint); switch (filterConstraint.getValueType()) { case STATIC: if (filterConstraint.isCapabilityPropertyFilter()) { return validateStaticValueAndOperatorOfCapabilityProperties(parentComponent, componentInstanceId, filterConstraint); } else { return validateStaticValueAndOperator(parentComponent, componentInstanceId, filterConstraint); } case GET_PROPERTY: return validatePropertyConstraint(parentComponent, componentInstanceId, filterConstraint, filterConstraint.getCapabilityName()); case GET_INPUT: return validateInputConstraint(parentComponent, componentInstanceId, filterConstraint); default: return Either.left(true); } } private void validateFilterConstraint(final FilterConstraintDto filterConstraint) { filterConstraintValidator.validate(filterConstraint); } private Either validatePropertyConstraint(final Component parentComponent, final String componentInstanceId, final FilterConstraintDto filterConstraint, final String capabilityName) { String source = SOURCE; ResponseFormat responseFormat = null; List toscaGetFunctionDataDefinitionList = new ArrayList<>(); final ToscaGetFunctionDataDefinition toscaGetFunction = filterConstraint.getAsToscaGetFunction().orElse(null); if (toscaGetFunction == null || !(filterConstraint.getValue() instanceof ToscaGetFunctionDataDefinition)) { final List toscaGetFunctionList = filterConstraint.getAsListToscaGetFunction().orElse(null); if (toscaGetFunctionList == null || toscaGetFunctionList.isEmpty() || !(filterConstraint.getValue() instanceof List)) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.TOSCA_FUNCTION_EXPECTED_ERROR)); } else { toscaGetFunctionDataDefinitionList = toscaGetFunctionList; } } else { toscaGetFunctionDataDefinitionList.add(toscaGetFunction); } Boolean allGood = true; for (ToscaGetFunctionDataDefinition _toscaGetFunction : toscaGetFunctionDataDefinitionList) { final Optional sourceSelectedProperty = findPropertyFromGetFunction(parentComponent, _toscaGetFunction); if (sourceSelectedProperty.isPresent()) { Optional targetComponentInstanceProperty = getInstanceProperties(parentComponent, componentInstanceId, capabilityName, filterConstraint); source = targetComponentInstanceProperty.isEmpty() ? TARGET : SOURCE; if (targetComponentInstanceProperty.isPresent()) { responseFormat = validatePropertyData(sourceSelectedProperty.get(), targetComponentInstanceProperty.get(), filterConstraint.getOperator().isLengthConstraint()); if (responseFormat != null) { allGood = false; break; } } else { allGood = false; final String missingProperty = SOURCE.equals(source) ? filterConstraint.getValue().toString() : filterConstraint.getPropertyName(); responseFormat = componentsUtils.getResponseFormat(ActionStatus.FILTER_PROPERTY_NOT_FOUND, source, missingProperty); break; } } else { allGood = false; final String missingProperty = SOURCE.equals(source) ? filterConstraint.getValue().toString() : filterConstraint.getPropertyName(); responseFormat = componentsUtils.getResponseFormat(ActionStatus.FILTER_PROPERTY_NOT_FOUND, source, missingProperty); break; } } if (allGood) { return Either.left(true); } return Either.right(responseFormat); } private Optional findPropertyFromGetFunction(final Component parentComponent, final ToscaGetFunctionDataDefinition toscaGetFunction) { List sourcePropertyDefinitions; if (PropertySource.SELF == toscaGetFunction.getPropertySource()) { sourcePropertyDefinitions = getSelfPropertyFromGetFunction(parentComponent, toscaGetFunction); } else { sourcePropertyDefinitions = getInstancePropertiesBasedOnGetFunctionSource(parentComponent, toscaGetFunction); } final List propertyPath = toscaGetFunction.getPropertyPathFromSource(); final Optional sourceProperty = sourcePropertyDefinitions.stream() .filter(propertyDefinition -> propertyDefinition.getName().equals(propertyPath.get(0))).findFirst(); if (sourceProperty.isEmpty() || propertyPath.size() == 1) { return sourceProperty; } final Either, JanusGraphOperationStatus> allDataTypesEither = applicationDataTypeCache.getAll(parentComponent.getModel()); if (allDataTypesEither.isRight()) { return Optional.empty(); } return findSubProperty(propertyPath.subList(1, propertyPath.size()), sourceProperty.get().getType(), allDataTypesEither.left().value()); } private List getInstancePropertiesBasedOnGetFunctionSource(final Component parentComponent, final ToscaGetFunctionDataDefinition toscaGetFunction) { final ComponentInstance componentInstance = parentComponent.getComponentInstances().stream() .filter(componentInstance1 -> componentInstance1.getName().equals(toscaGetFunction.getSourceName())) .findFirst() .orElse(null); if (componentInstance == null) { return List.of(); } final List instanceProperties; switch (toscaGetFunction.getFunctionType()) { case GET_PROPERTY: instanceProperties = parentComponent.getComponentInstancesProperties().get(componentInstance.getUniqueId()); break; case GET_ATTRIBUTE: instanceProperties = parentComponent.getComponentInstancesAttributes().get(componentInstance.getUniqueId()); break; default: instanceProperties = List.of(); } if (instanceProperties == null) { return List.of(); } return instanceProperties; } private Optional findSubProperty(final List propertyPath, final String parentPropertyType, final Map modelDataTypes) { final DataTypeDefinition dataTypeDefinition = modelDataTypes.get(parentPropertyType); if (CollectionUtils.isEmpty(dataTypeDefinition.getProperties())) { return Optional.empty(); } final PropertyDefinition propertyDefinition = dataTypeDefinition.getProperties().stream() .filter(propertyDefinition1 -> propertyDefinition1.getName().equals(propertyPath.get(0))).findFirst().orElse(null); if (propertyDefinition == null) { return Optional.empty(); } if (propertyPath.size() == 1) { return Optional.of(propertyDefinition); } return findSubProperty(propertyPath.subList(1, propertyPath.size()), propertyDefinition.getType(), modelDataTypes); } private Optional getInstanceProperties(final Component parentComponent, final String componentInstanceId, final String capabilityName, final FilterConstraintDto filterConstraint) { if (StringUtils.isEmpty(capabilityName)) { OriginTypeEnum componentInstanceType = getComponentInstanceOriginType(parentComponent, componentInstanceId); if (componentInstanceType == null) { return Optional.empty(); } PropertyDefinition componentInstanceProperty = getComponentInstanceProperty(componentInstanceType, parentComponent, componentInstanceId, filterConstraint); if (componentInstanceProperty == null) { throw new ByActionStatusComponentException(ActionStatus.SELECTED_PROPERTY_NOT_PRESENT, filterConstraint.getPropertyName()); } if (componentInstanceProperty instanceof ComponentInstanceInput) { return parentComponent.getComponentInstancesInputs().get(componentInstanceId).stream() .filter(property -> filterConstraint.getPropertyName().equals(property.getName())).findFirst(); } return parentComponent.getComponentInstancesProperties().get(componentInstanceId).stream() .filter(property -> filterConstraint.getPropertyName().equals(property.getName())).findFirst(); } else { final Optional componentInstanceOptional = parentComponent.getComponentInstances().stream() .filter(componentInstance -> componentInstance.getUniqueId().equals(componentInstanceId)).findAny(); if (componentInstanceOptional.isPresent()) { for (final List listOfCaps : componentInstanceOptional.get().getCapabilities().values()) { final Optional capDef = listOfCaps.stream().filter(cap -> cap.getName().equals(capabilityName)).findAny(); if (capDef.isPresent()) { return capDef.get().getProperties().stream().filter(property -> filterConstraint.getPropertyName().equals(property.getName())) .findFirst(); } } } } return Optional.empty(); } private Either validateInputConstraint(final Component parentComponent, final String componentInstanceId, final FilterConstraintDto filterConstraint) { final List sourceInputDefinition = parentComponent.getInputs(); if (CollectionUtils.isEmpty(sourceInputDefinition)) { LOGGER.debug("Parent component '{}', unique id '{}', does not have inputs", parentComponent.getName(), parentComponent.getUniqueId()); return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_DOES_NOT_HAVE_INPUTS, parentComponent.getName())); } if (!(filterConstraint.getValue() instanceof ToscaGetFunctionDataDefinition)) { if (filterConstraint.getValue() instanceof List) { Optional optValid = ((List) filterConstraint.getValue()).stream().filter(filterConstraintValue -> !(filterConstraintValue instanceof ToscaGetFunctionDataDefinition)).findAny(); if (optValid.isPresent()) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.TOSCA_FUNCTION_EXPECTED_ERROR)); } } else { return Either.right(componentsUtils.getResponseFormat(ActionStatus.TOSCA_FUNCTION_EXPECTED_ERROR)); } } if (filterConstraint.getValue() instanceof ToscaGetFunctionDataDefinition) { final ToscaGetFunctionDataDefinition getFunction = (ToscaGetFunctionDataDefinition) filterConstraint.getValue(); final List propertyPathFromSource = getFunction.getPropertyPathFromSource(); Optional sourceSelectedProperty = sourceInputDefinition.stream().filter(input -> input.getName().equals(propertyPathFromSource.get(0))) .findFirst(); if (sourceSelectedProperty.isEmpty()) { LOGGER.debug(INPUT_NOT_FOUND_LOG, propertyPathFromSource.get(0), parentComponent.getName(), parentComponent.getUniqueId()); return Either.right( componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INPUT_NOT_FOUND, propertyPathFromSource.get(0), parentComponent.getName()) ); } if (propertyPathFromSource.size() > 1) { final Either, JanusGraphOperationStatus> allDataTypesEither = applicationDataTypeCache.getAll(parentComponent.getModel()); if (allDataTypesEither.isRight()) { LOGGER.error("Could not load data types for model {}", parentComponent.getModel()); return Either.right(componentsUtils.getResponseFormat(ActionStatus.DATA_TYPES_NOT_LOADED, parentComponent.getModel())); } sourceSelectedProperty = findSubProperty(propertyPathFromSource.subList(1, propertyPathFromSource.size()), sourceSelectedProperty.get().getType(), allDataTypesEither.left().value()); } final Optional targetComponentInstanceProperty; if (PropertyFilterTargetType.CAPABILITY.equals(filterConstraint.getTargetType())) { final CapabilityDefinition capability = parentComponent.getComponentInstances().stream() .filter(componentInstance -> componentInstance.getUniqueId().equals(componentInstanceId)) .map(componentInstance -> componentInstance.getCapabilities().values()) .flatMap(Collection::stream) .flatMap(Collection::stream) .filter(capabilityDefinition -> capabilityDefinition.getName() .equals(filterConstraint.getCapabilityName())) .findFirst().orElse(null); if (capability == null) { return Either.right( componentsUtils.getResponseFormat(ActionStatus.CAPABILITY_NOT_FOUND_IN_COMPONENT, filterConstraint.getCapabilityName(), parentComponent.getComponentType().getValue(), parentComponent.getName()) ); } targetComponentInstanceProperty = capability.getProperties().stream() .filter(property -> filterConstraint.getPropertyName().equals(property.getName())) .findFirst(); } else { targetComponentInstanceProperty = parentComponent.getComponentInstancesProperties() .get(componentInstanceId).stream() .filter(property -> filterConstraint.getPropertyName().equals(property.getName())) .findFirst(); } if (sourceSelectedProperty.isPresent() && targetComponentInstanceProperty.isPresent()) { final ResponseFormat responseFormat = validatePropertyData(sourceSelectedProperty.get(), targetComponentInstanceProperty.get(), filterConstraint.getOperator().isLengthConstraint()); if (responseFormat != null) { return Either.right(responseFormat); } return Either.left(true); } return Either.right(componentsUtils.getResponseFormat(ActionStatus.INPUTS_NOT_FOUND)); } return Either.left(true); } private ResponseFormat validatePropertyData(final T sourcePropDefinition, final T targetPropDefinition, final boolean isLengthConstraint) { final String sourceType = sourcePropDefinition.getType(); final String targetType = targetPropDefinition.getType(); if (!isLengthConstraint) { if (sourceType.equals(targetType)) { if (TYPES_WITH_SCHEMA.contains(sourceType)) { final String sourceSchemaType = sourcePropDefinition.getSchemaType(); final String targetSchemaType = targetPropDefinition.getSchemaType(); if (sourceSchemaType != null && !sourceSchemaType.equals(targetSchemaType)) { return componentsUtils.getResponseFormat(ActionStatus.SOURCE_TARGET_SCHEMA_MISMATCH, targetPropDefinition.getName(), targetSchemaType, sourcePropDefinition.getName(), sourceSchemaType); } } return null; } else { if (null != ((PropertyDefinition) sourcePropDefinition).getSchemaProperty()) { if (((PropertyDefinition) sourcePropDefinition).getSchemaProperty().getType().equals(targetType)) { if (TYPES_WITH_SCHEMA.contains(((PropertyDefinition) sourcePropDefinition).getSchemaProperty().getType())) { final String sourceSchemaType = sourcePropDefinition.getSchemaType(); final String targetSchemaType = targetPropDefinition.getSchemaType(); if (sourceSchemaType != null && !sourceSchemaType.equals(targetSchemaType)) { return componentsUtils.getResponseFormat(ActionStatus.SOURCE_TARGET_SCHEMA_MISMATCH, targetPropDefinition.getName(), targetSchemaType, sourcePropDefinition.getName(), sourceSchemaType); } } return null; } } } } else { if (sourceType.equalsIgnoreCase("integer")) { if (TYPES_WITH_SCHEMA.contains(sourceType)) { final String sourceSchemaType = sourcePropDefinition.getSchemaType(); if (sourceSchemaType != null && !sourceSchemaType.equalsIgnoreCase("integer")) { return componentsUtils.getResponseFormat(ActionStatus.SOURCE_TARGET_SCHEMA_MISMATCH, targetPropDefinition.getName(), "integer", sourcePropDefinition.getName(), sourceSchemaType); } } return null; } } return componentsUtils.getResponseFormat(ActionStatus.SOURCE_TARGET_PROPERTY_TYPE_MISMATCH, sourcePropDefinition.getName(), sourcePropDefinition.getType(), targetPropDefinition.getName(), targetPropDefinition.getType()); } private Either validateStaticValueAndOperator(final Component parentComponent, final String componentInstanceId, final FilterConstraintDto filterConstraint) { OriginTypeEnum componentInstanceType = getComponentInstanceOriginType(parentComponent, componentInstanceId); if (componentInstanceType == null) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND, componentInstanceId)); } PropertyDefinition componentInstanceProperty = getComponentInstanceProperty(componentInstanceType, parentComponent, componentInstanceId, filterConstraint); if (componentInstanceProperty == null) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.SELECTED_PROPERTY_NOT_PRESENT, filterConstraint.getPropertyName())); } if (filterConstraint.getOperator().isComparable() && !TYPES_WITH_SCHEMA.contains(componentInstanceProperty.getType()) && !COMPARABLE_TYPES.contains(componentInstanceProperty.getType())) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_OPERATOR_PROVIDED, filterConstraint.getPropertyName(), filterConstraint.getOperator().getType())); } if (filterConstraint.getOperator().equals(ConstraintType.VALID_VALUES) || filterConstraint.getOperator().equals(ConstraintType.IN_RANGE)) { return isValidValueCheck("list", componentInstanceProperty.getType(), parentComponent.getModel(), filterConstraint.getValue(), filterConstraint.getPropertyName()); } if (filterConstraint.getOperator().isLengthConstraint() && componentInstanceProperty.getType().equals("list")) { return Either.left(true); } return isValidValueCheck(componentInstanceProperty.getType(), componentInstanceProperty.getSchemaType(), parentComponent.getModel(), filterConstraint.getValue(), filterConstraint.getPropertyName()); } private PropertyDefinition getComponentInstanceProperty(OriginTypeEnum componentInstanceType, Component parentComponent, String componentInstanceId, FilterConstraintDto filterConstraint) { if (isInput(componentInstanceType)) { return parentComponent.getComponentInstancesInputs() .get(componentInstanceId).stream().filter(input -> filterConstraint.getPropertyName().equals(input.getName())) .findFirst() .orElse(null); } return parentComponent.getComponentInstancesProperties() .get(componentInstanceId).stream().filter(property -> filterConstraint.getPropertyName().equals(property.getName())) .findFirst() .orElse(null); } private OriginTypeEnum getComponentInstanceOriginType(Component parentComponent, String componentInstanceId) { Optional componentInstanceOptional = parentComponent.getComponentInstanceById(componentInstanceId); if (componentInstanceOptional.isPresent()) { ComponentInstance componentInstance = componentInstanceOptional.get(); return componentInstance.getOriginType(); } return null; } private boolean isInput(OriginTypeEnum instanceType) { return OriginTypeEnum.VF.equals(instanceType) || OriginTypeEnum.PNF.equals(instanceType) || OriginTypeEnum.CVFC.equals(instanceType) || OriginTypeEnum.CR.equals(instanceType); } private Either validateStaticSubstitutionFilter(final Component component, final FilterConstraintDto filterConstraint) { final PropertyDefinition componentProperty = component.getProperties().stream() .filter(property -> property.getName().equals(filterConstraint.getPropertyName())).findFirst().orElse(null); if (componentProperty == null) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.SELECTED_PROPERTY_NOT_PRESENT, filterConstraint.getPropertyName())); } if (filterConstraint.getOperator().isComparable() && !TYPES_WITH_SCHEMA.contains(componentProperty.getType()) && !COMPARABLE_TYPES.contains(componentProperty.getType())) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_OPERATOR_PROVIDED, filterConstraint.getPropertyName(), filterConstraint.getOperator().getType())); } if (filterConstraint.getOperator().equals(ConstraintType.VALID_VALUES) || filterConstraint.getOperator().equals(ConstraintType.IN_RANGE)) { return isValidValueCheck("list", componentProperty.getType(), component.getModel(), filterConstraint.getValue(), filterConstraint.getPropertyName()); } return isValidValueCheck(componentProperty.getType(), componentProperty.getSchemaType(), component.getModel(), filterConstraint.getValue(), filterConstraint.getPropertyName()); } private Either validateStaticValueAndOperatorOfCapabilityProperties(final Component parentComponent, final String componentInstanceId, final FilterConstraintDto filterConstraint) { ComponentInstanceProperty componentInstanceProperty = null; final Optional optionalComponentInstances = parentComponent.getComponentInstances().stream() .filter(componentInstance -> componentInstanceId.equalsIgnoreCase(componentInstance.getUniqueId())).findFirst(); if (optionalComponentInstances.isPresent()) { final Optional> optionalCapabilityDefinitionList = optionalComponentInstances.get().getCapabilities().values() .stream().filter(capabilityDefinitions -> capabilityDefinitions.stream() .allMatch(capabilityDefinition -> capabilityDefinition.getProperties() != null)).collect(Collectors.toList()).stream().filter( capabilityDefinitions -> capabilityDefinitions.stream().allMatch( capabilityDefinition -> capabilityDefinition.getProperties().stream().anyMatch( componentInstanceProperty1 -> filterConstraint.getPropertyName() .equalsIgnoreCase(componentInstanceProperty1.getName())))).findFirst(); if (optionalCapabilityDefinitionList.isPresent() && !optionalCapabilityDefinitionList.get().isEmpty()) { componentInstanceProperty = getComponentInstanceProperty(optionalCapabilityDefinitionList.get().get(0), filterConstraint.getPropertyName()).orElse(null); } } if (componentInstanceProperty == null) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.SELECTED_PROPERTY_NOT_PRESENT, filterConstraint.getPropertyName())); } if (filterConstraint.getOperator().isComparable() && !TYPES_WITH_SCHEMA.contains(componentInstanceProperty.getType()) && !COMPARABLE_TYPES.contains(componentInstanceProperty.getType())) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_OPERATOR_PROVIDED, filterConstraint.getPropertyName(), filterConstraint.getOperator().getType())); } return isValidValueCheck(componentInstanceProperty.getType(), componentInstanceProperty.getSchemaType(), parentComponent.getModel(), filterConstraint.getValue(), filterConstraint.getPropertyName()); } private Optional getComponentInstanceProperty(CapabilityDefinition capabilityDefinition, final String propertyName) { return capabilityDefinition.getProperties().stream().filter(property -> property.getName().equals(propertyName)).findAny(); } private Either isValidValueCheck(final String type, final String schemaType, final String model, final Object value, final String propertyName) { final Either, JanusGraphOperationStatus> allDataTypesEither = applicationDataTypeCache.getAll(model); if (allDataTypesEither.isRight()) { LOGGER.error("Could not validate filter value. Could not load data types for model {}", model); return Either.right(componentsUtils.getResponseFormat(ActionStatus.DATA_TYPES_NOT_LOADED, model)); } final Map modelDataTypesMap = allDataTypesEither.left().value(); final ToscaPropertyType toscaPropertyType = ToscaPropertyType.isValidType(type); if (toscaPropertyType == null && !modelDataTypesMap.containsKey(type)) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_PROPERTY_TYPE, type, propertyName)); } final String valueAsJsonString; try { valueAsJsonString = new Gson().toJson(value); } catch (final Exception e) { LOGGER.debug("Unsupported property filter value", e); return Either.right( componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_VALUE_PROVIDED, type, propertyName, String.valueOf(value))); } if (toscaPropertyType != null) { if (toscaPropertyType.getValidator().isValid(valueAsJsonString, schemaType, modelDataTypesMap)) { return Either.left(true); } } else { if (DataTypeValidatorConverter.getInstance().isValid(valueAsJsonString, modelDataTypesMap.get(type), modelDataTypesMap)) { return Either.left(true); } } return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_VALUE_PROVIDED, type, propertyName, valueAsJsonString)); } public Either validateSubstitutionFilter(final Component component, final List filterConstraintList) { if (CollectionUtils.isEmpty(filterConstraintList)) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.CONSTRAINT_FORMAT_INCORRECT)); } for (final FilterConstraintDto filterConstraintDto : filterConstraintList) { final Either validationEither = validateSubstitutionFilter(component, filterConstraintDto); if (validationEither.isRight()) { return validationEither; } } return Either.left(true); } public Either validateSubstitutionFilter(final Component component, final FilterConstraintDto filterConstraint) { validateFilterConstraint(filterConstraint); switch (filterConstraint.getValueType()) { case STATIC: return validateStaticSubstitutionFilter(component, filterConstraint); case GET_PROPERTY: case GET_ATTRIBUTE: case GET_INPUT: return validateSubstitutionFilterGetFunctionConstraint(component, filterConstraint); default: return Either.left(true); } } private Either validateSubstitutionFilterGetFunctionConstraint(final Component component, final FilterConstraintDto filterConstraint) { final ToscaGetFunctionDataDefinition toscaGetFunction = filterConstraint.getAsToscaGetFunction().orElse(null); if (toscaGetFunction == null) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.TOSCA_FUNCTION_EXPECTED_ERROR)); } if (CollectionUtils.isEmpty(component.getProperties())) { return Either.right( componentsUtils.getResponseFormat(ActionStatus.FILTER_PROPERTY_NOT_FOUND, TARGET, getPropertyType(toscaGetFunction), filterConstraint.getPropertyName()) ); } final Optional targetComponentProperty = component.getProperties().stream() .filter(property -> property.getName().equals(filterConstraint.getPropertyName())).findFirst(); if (targetComponentProperty.isEmpty()) { return Either.right( componentsUtils.getResponseFormat(ActionStatus.FILTER_PROPERTY_NOT_FOUND, TARGET, getPropertyType(toscaGetFunction), filterConstraint.getPropertyName()) ); } final Optional sourceSelectedProperty = findPropertyFromGetFunction(component, toscaGetFunction); if (sourceSelectedProperty.isEmpty()) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.FILTER_PROPERTY_NOT_FOUND, SOURCE, getPropertyType(toscaGetFunction), String.join("->", toscaGetFunction.getPropertyPathFromSource()))); } final ResponseFormat responseFormat = validatePropertyData(sourceSelectedProperty.get(), targetComponentProperty.get(), filterConstraint.getOperator().isLengthConstraint()); if (responseFormat != null) { return Either.right(responseFormat); } return Either.left(true); } private String getPropertyType(final ToscaGetFunctionDataDefinition toscaGetFunction) { switch (toscaGetFunction.getType()) { case GET_INPUT: return "input"; case GET_PROPERTY: return "property"; case GET_ATTRIBUTE: return "attribute"; default: return ""; } } }