2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
20 package org.openecomp.sdc.be.components.validation;
22 import com.google.common.collect.ImmutableSet;
23 import fj.data.Either;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.List;
27 import java.util.Objects;
28 import java.util.Optional;
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.components.impl.ResponseFormatManager;
34 import org.openecomp.sdc.be.components.impl.utils.NodeFilterConstraintAction;
35 import org.openecomp.sdc.be.dao.api.ActionStatus;
36 import org.openecomp.sdc.be.datamodel.utils.ConstraintConvertor;
37 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
38 import org.openecomp.sdc.be.datatypes.enums.NodeFilterConstraintType;
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.InputDefinition;
45 import org.openecomp.sdc.be.model.PropertyDefinition;
46 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
47 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
48 import org.openecomp.sdc.be.ui.model.UIConstraint;
49 import org.openecomp.sdc.exception.ResponseFormat;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52 import org.springframework.beans.factory.annotation.Autowired;
54 @org.springframework.stereotype.Component("NodeFilterValidator")
55 public class NodeFilterValidator {
57 private static final String SOURCE = "Source";
58 public static final Set<String> comparableTypes = ImmutableSet
59 .of(ToscaPropertyType.STRING.getType(), ToscaPropertyType.INTEGER.getType(), ToscaPropertyType.FLOAT.getType());
60 public static final Set<String> schemableTypes = ImmutableSet.of(ToscaPropertyType.MAP.getType(), ToscaPropertyType.LIST.getType());
61 public static final Set<String> comparableConstraintsOperators = ImmutableSet
62 .of(ConstraintConvertor.GREATER_THAN_OPERATOR, ConstraintConvertor.LESS_THAN_OPERATOR);
63 protected final ToscaOperationFacade toscaOperationFacade;
64 protected final ComponentsUtils componentsUtils;
65 private static final Logger LOGGER = LoggerFactory.getLogger(NodeFilterValidator.class);
68 public NodeFilterValidator(final ToscaOperationFacade toscaOperationFacade, final ComponentsUtils componentsUtils) {
69 this.toscaOperationFacade = toscaOperationFacade;
70 this.componentsUtils = componentsUtils;
73 public Either<Boolean, ResponseFormat> validateComponentInstanceExist(final Component component, final String componentInstanceId) {
74 if (component == null || StringUtils.isEmpty(componentInstanceId)) {
75 LOGGER.error("Input data cannot be empty");
76 return getErrorResponse(ActionStatus.FILTER_NOT_FOUND);
78 if (CollectionUtils.isEmpty(component.getComponentInstances()) || component.getComponentInstances().stream()
79 .noneMatch(ci -> ci.getUniqueId().equals(componentInstanceId))) {
80 LOGGER.error("Component Instance list is empty");
81 return getErrorResponse(ActionStatus.FILTER_NOT_FOUND);
83 return Either.left(Boolean.TRUE);
86 private Either<Boolean, ResponseFormat> getErrorResponse(ActionStatus actionStatus, String... variables) {
87 ResponseFormat errorResponse = ResponseFormatManager.getInstance().getResponseFormat(actionStatus, variables);
88 return Either.right(errorResponse);
91 public Either<Boolean, ResponseFormat> validateFilter(final Component parentComponent, final String componentInstanceId,
92 final List<String> uiConstraints, final NodeFilterConstraintAction action,
93 final NodeFilterConstraintType nodeFilterConstraintType) {
95 if (NodeFilterConstraintAction.ADD == action || NodeFilterConstraintAction.UPDATE == action) {
96 for (final String uiConstraint : uiConstraints) {
97 final UIConstraint constraint = new ConstraintConvertor().convert(uiConstraint);
98 if (ConstraintConvertor.PROPERTY_CONSTRAINT.equals(constraint.getSourceType())) {
99 final Either<Boolean, ResponseFormat> booleanResponseFormatEither = validatePropertyConstraint(parentComponent,
100 componentInstanceId, constraint);
101 if (booleanResponseFormatEither.isRight()) {
102 return booleanResponseFormatEither;
105 else if (ConstraintConvertor.SERVICE_INPUT_CONSTRAINT.equals(constraint.getSourceType())) {
106 final Either<Boolean, ResponseFormat> booleanResponseFormatEither = validateInputConstraint(parentComponent,
107 componentInstanceId, constraint);
108 if (booleanResponseFormatEither.isRight()) {
109 return booleanResponseFormatEither;
112 else if (ConstraintConvertor.STATIC_CONSTRAINT.equals(constraint.getSourceType())) {
113 Either<Boolean, ResponseFormat> booleanResponseFormatEither;
114 if (NodeFilterConstraintType.PROPERTIES.equals(nodeFilterConstraintType)) {
115 booleanResponseFormatEither = isComponentPropertyFilterValid(parentComponent, componentInstanceId, constraint);
117 booleanResponseFormatEither = isComponentCapabilityPropertyFilterValid(parentComponent, componentInstanceId, constraint);
119 if (booleanResponseFormatEither.isRight()) {
120 return booleanResponseFormatEither;
125 } catch (final Exception e) {
126 LOGGER.debug("Provided constraint" + uiConstraints, e);
127 return Either.right(componentsUtils.getResponseFormat(ActionStatus.CONSTRAINT_FORMAT_INCORRECT));
129 return Either.left(true);
132 private Either<Boolean, ResponseFormat> isComponentCapabilityPropertyFilterValid(final Component parentComponent,
133 final String componentInstanceId,
134 final UIConstraint uiConstraint) {
135 return validateStaticValueAndOperatorOfCapabilityProperties(parentComponent, componentInstanceId, uiConstraint);
138 private Either<Boolean, ResponseFormat> isComponentPropertyFilterValid(Component parentComponent, String componentInstanceId,
139 UIConstraint constraint) {
140 return validateStaticValueAndOperator(parentComponent, componentInstanceId, constraint);
143 private Either<Boolean, ResponseFormat> validatePropertyConstraint(final Component parentComponent, final String componentInstanceId,
144 final UIConstraint uiConstraint) {
145 String source = SOURCE;
146 final Optional<ComponentInstance> optionalComponentInstance;
147 final List<PropertyDefinition> propertyDefinitions = parentComponent.getProperties();
148 final var SELF = "SELF";
149 List<? extends PropertyDefinition> sourcePropertyDefinition =
150 SELF.equalsIgnoreCase(uiConstraint.getSourceName()) && propertyDefinitions != null ? propertyDefinitions
151 : Collections.emptyList();
152 if (sourcePropertyDefinition.isEmpty() && !SELF.equalsIgnoreCase(uiConstraint.getSourceName())) {
153 optionalComponentInstance = parentComponent.getComponentInstances().stream()
154 .filter(componentInstance -> uiConstraint.getSourceName().equals(componentInstance.getName())).findFirst();
155 if (optionalComponentInstance.isPresent()) {
156 final List<ComponentInstanceProperty> componentInstanceProperties = parentComponent.getComponentInstancesProperties()
157 .get(optionalComponentInstance.get().getUniqueId());
158 sourcePropertyDefinition = componentInstanceProperties == null ? new ArrayList<>() : componentInstanceProperties;
161 if (CollectionUtils.isNotEmpty(sourcePropertyDefinition)) {
162 final Optional<? extends PropertyDefinition> sourceSelectedProperty = sourcePropertyDefinition.stream()
163 .filter(property -> uiConstraint.getValue().equals(property.getName())).findFirst();
164 final Optional<? extends PropertyDefinition> targetComponentInstanceProperty = parentComponent.getComponentInstancesProperties()
165 .get(componentInstanceId).stream().filter(property -> uiConstraint.getServicePropertyName().equals(property.getName())).findFirst();
166 source = !targetComponentInstanceProperty.isPresent() ? "Target" : SOURCE;
167 if (sourceSelectedProperty.isPresent() && targetComponentInstanceProperty.isPresent()) {
168 return validatePropertyData(uiConstraint, sourceSelectedProperty, targetComponentInstanceProperty);
171 final String missingProperty = source.equals(SOURCE) ? uiConstraint.getValue().toString() : uiConstraint.getServicePropertyName();
172 return Either.right(componentsUtils.getResponseFormat(ActionStatus.MAPPED_PROPERTY_NOT_FOUND, source, missingProperty));
175 private Either<Boolean, ResponseFormat> validateInputConstraint(final Component parentComponent, final String componentInstanceId,
176 final UIConstraint uiConstraint) {
177 final List<InputDefinition> sourceInputDefinition = parentComponent.getInputs();
178 if (CollectionUtils.isNotEmpty(sourceInputDefinition)) {
179 final Optional<? extends InputDefinition> sourceSelectedProperty = sourceInputDefinition.stream()
180 .filter(input -> uiConstraint.getValue().equals(input.getName())).findFirst();
181 final Optional<? extends PropertyDefinition> targetComponentInstanceProperty = parentComponent.getComponentInstancesProperties()
182 .get(componentInstanceId).stream().filter(property -> uiConstraint.getServicePropertyName().equals(property.getName())).findFirst();
183 if (sourceSelectedProperty.isPresent() && targetComponentInstanceProperty.isPresent()) {
184 return validatePropertyData(uiConstraint, sourceSelectedProperty, targetComponentInstanceProperty);
187 LOGGER.debug("Parent component does not have inputs", parentComponent);
188 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INPUTS_NOT_FOUND));
191 private Either<Boolean, ResponseFormat> validatePropertyData(UIConstraint uiConstraint,
192 Optional<? extends PropertyDefinition> sourceSelectedProperty,
193 Optional<? extends PropertyDefinition> targetComponentInstanceProperty) {
194 if (sourceSelectedProperty.isPresent() && targetComponentInstanceProperty.isPresent()) {
195 final PropertyDefinition sourcePropDefinition = sourceSelectedProperty.get();
196 final String sourceType = sourcePropDefinition.getType();
197 final PropertyDefinition targetPropDefinition = targetComponentInstanceProperty.get();
198 final String targetType = targetPropDefinition.getType();
199 if (sourceType.equals(targetType)) {
200 if (schemableTypes.contains(sourceType)) {
201 final SchemaDefinition sourceSchemaDefinition = sourcePropDefinition.getSchema();
202 final SchemaDefinition targetSchemaDefinition = targetPropDefinition.getSchema();
203 if (!sourceSchemaDefinition.equals(targetSchemaDefinition)) {
204 return Either.right(componentsUtils
205 .getResponseFormat(ActionStatus.SOURCE_TARGET_SCHEMA_MISMATCH, uiConstraint.getServicePropertyName(),
206 uiConstraint.getValue().toString()));
209 return Either.left(Boolean.TRUE);
211 return Either.right(componentsUtils
212 .getResponseFormat(ActionStatus.SOURCE_TARGET_PROPERTY_TYPE_MISMATCH, uiConstraint.getServicePropertyName(),
213 uiConstraint.getValue().toString()));
216 LOGGER.debug("Null value passed to `validatePropertyData` - sourceSelectedProperty: '{}' - targetComponentInstanceProperty: '{}'",
217 sourceSelectedProperty, targetComponentInstanceProperty);
218 return Either.right(componentsUtils
219 .getResponseFormat(ActionStatus.GENERAL_ERROR, uiConstraint.getServicePropertyName(), uiConstraint.getValue().toString()));
223 private Either<Boolean, ResponseFormat> validateStaticValueAndOperator(final Component parentComponent, final String componentInstanceId,
224 final UIConstraint uiConstraint) {
225 if (!(Objects.nonNull(uiConstraint) && uiConstraint.getValue() instanceof String)) {
226 return Either.left(false);
228 //TODO: get capabilities properties when constraint type is capabilities
229 final Optional<ComponentInstanceProperty> componentInstanceProperty = parentComponent.getComponentInstancesProperties()
230 .get(componentInstanceId).stream().filter(property -> uiConstraint.getServicePropertyName().equals(property.getName())).findFirst();
231 if (!componentInstanceProperty.isPresent()) {
232 return Either.right(componentsUtils.getResponseFormat(ActionStatus.SELECTED_PROPERTY_NOT_PRESENT, uiConstraint.getServicePropertyName()));
234 if (comparableConstraintsOperators.contains(uiConstraint.getConstraintOperator()) && !comparableTypes
235 .contains(componentInstanceProperty.get().getType())) {
236 return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_OPERATOR_PROVIDED, uiConstraint.getServicePropertyName(),
237 uiConstraint.getConstraintOperator()));
239 return isValidValueCheck(componentInstanceProperty.get().getType(), String.valueOf(uiConstraint.getValue()),
240 uiConstraint.getServicePropertyName());
243 private Either<Boolean, ResponseFormat> validateStaticValueAndOperatorOfCapabilityProperties(final Component parentComponent,
244 final String componentInstanceId,
245 final UIConstraint uiConstraint) {
246 if (!(Objects.nonNull(uiConstraint) && uiConstraint.getValue() instanceof String)) {
247 return Either.left(false);
249 Optional<ComponentInstanceProperty> optionalComponentInstanceProperty = Optional.empty();
250 final Optional<ComponentInstance> optionalComponentInstances = parentComponent.getComponentInstances().stream()
251 .filter(componentInstance -> componentInstanceId.equalsIgnoreCase(componentInstance.getUniqueId())).findFirst();
252 if (optionalComponentInstances.isPresent()) {
253 final Optional<List<CapabilityDefinition>> optionalCapabilityDefinitionList = optionalComponentInstances.get().getCapabilities().values()
254 .stream().filter(capabilityDefinitions -> capabilityDefinitions.stream()
255 .allMatch(capabilityDefinition -> capabilityDefinition.getProperties() != null)).collect(Collectors.toList()).stream().filter(
256 capabilityDefinitions -> capabilityDefinitions.stream().allMatch(
257 capabilityDefinition -> capabilityDefinition.getProperties().stream().anyMatch(
258 componentInstanceProperty -> uiConstraint.getServicePropertyName()
259 .equalsIgnoreCase(componentInstanceProperty.getName())))).findFirst();
260 if (optionalCapabilityDefinitionList.isPresent() && !optionalCapabilityDefinitionList.get().isEmpty()) {
261 optionalComponentInstanceProperty = getComponentInstanceProperty(optionalCapabilityDefinitionList.get().get(0), uiConstraint.getServicePropertyName());
265 if (optionalComponentInstanceProperty.isEmpty()) {
266 return Either.right(componentsUtils.getResponseFormat(ActionStatus.SELECTED_PROPERTY_NOT_PRESENT, uiConstraint.getServicePropertyName()));
268 if (comparableConstraintsOperators.contains(uiConstraint.getConstraintOperator()) && !comparableTypes
269 .contains(optionalComponentInstanceProperty.get().getType())) {
270 return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_OPERATOR_PROVIDED, uiConstraint.getServicePropertyName(),
271 uiConstraint.getConstraintOperator()));
273 return isValidValueCheck(optionalComponentInstanceProperty.get().getType(), String.valueOf(uiConstraint.getValue()),
274 uiConstraint.getServicePropertyName());
277 private Optional<ComponentInstanceProperty> getComponentInstanceProperty(CapabilityDefinition capabilityDefinition, final String propertyName){
278 return capabilityDefinition.getProperties().stream().filter(property -> property.getName().equals(propertyName)).findAny();
281 private Either<Boolean, ResponseFormat> isValidValueCheck(String type, String value, String propertyName) {
282 ToscaPropertyType toscaPropertyType = ToscaPropertyType.isValidType(type);
283 if (Objects.isNull(toscaPropertyType)) {
284 return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_PROPERTY_TYPE, type, propertyName));
286 if (toscaPropertyType.getValidator().isValid(value, null)) {
287 return Either.left(Boolean.TRUE);
289 return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_VALUE_PROVIDED, type, propertyName, value));
292 public Either<Boolean, ResponseFormat> validateComponentFilter(final Component component, final List<String> uiConstraints,
293 final NodeFilterConstraintAction action) {
295 if (NodeFilterConstraintAction.ADD == action || NodeFilterConstraintAction.UPDATE == action) {
296 for (final String uiConstraint : uiConstraints) {
297 final UIConstraint constraint = new ConstraintConvertor().convert(uiConstraint);
298 if (ConstraintConvertor.PROPERTY_CONSTRAINT.equals(constraint.getSourceType())) {
299 final Either<Boolean, ResponseFormat> booleanResponseFormatEither = validateComponentPropertyConstraint(component,
301 if (booleanResponseFormatEither.isRight()) {
302 return booleanResponseFormatEither;
304 } else if (ConstraintConvertor.STATIC_CONSTRAINT.equals(constraint.getSourceType())) {
305 final Either<Boolean, ResponseFormat> booleanResponseFormatEither = validateComponentStaticValueAndOperator(component,
307 if (booleanResponseFormatEither.isRight()) {
308 return booleanResponseFormatEither;
313 } catch (final Exception e) {
314 LOGGER.debug("Provided constraint" + uiConstraints, e);
315 return Either.right(componentsUtils.getResponseFormat(ActionStatus.CONSTRAINT_FORMAT_INCORRECT));
317 return Either.left(true);
320 private Either<Boolean, ResponseFormat> validateComponentPropertyConstraint(final Component component, final UIConstraint uiConstraint) {
321 String source = SOURCE;
322 final List<PropertyDefinition> propertyDefinitions = component.getProperties();
323 List<? extends PropertyDefinition> sourcePropertyDefinition =
324 component.getName().equals(uiConstraint.getSourceName()) && propertyDefinitions != null ? propertyDefinitions : Collections.emptyList();
325 if (CollectionUtils.isNotEmpty(sourcePropertyDefinition)) {
326 final Optional<? extends PropertyDefinition> sourceSelectedProperty = sourcePropertyDefinition.stream()
327 .filter(property -> uiConstraint.getValue().equals(property.getName())).findFirst();
328 final Optional<? extends PropertyDefinition> targetComponentProperty = component.getProperties().stream()
329 .filter(property -> uiConstraint.getServicePropertyName().equals(property.getName())).findFirst();
330 source = !targetComponentProperty.isPresent() ? "Target" : SOURCE;
331 if (sourceSelectedProperty.isPresent() && targetComponentProperty.isPresent()) {
332 return validatePropertyData(uiConstraint, sourceSelectedProperty, targetComponentProperty);
335 final String missingProperty = source.equals(SOURCE) ? uiConstraint.getValue().toString() : uiConstraint.getServicePropertyName();
336 return Either.right(componentsUtils.getResponseFormat(ActionStatus.MAPPED_PROPERTY_NOT_FOUND, source, missingProperty));
339 private Either<Boolean, ResponseFormat> validateComponentStaticValueAndOperator(final Component component, final UIConstraint uiConstraint) {
340 if (!(Objects.nonNull(uiConstraint) && uiConstraint.getValue() instanceof String)) {
341 return Either.left(false);
343 final Optional<PropertyDefinition> componentProperty = component.getProperties().stream()
344 .filter(property -> uiConstraint.getServicePropertyName().equals(property.getName())).findFirst();
345 if (componentProperty.isEmpty()) {
346 return Either.right(componentsUtils.getResponseFormat(ActionStatus.SELECTED_PROPERTY_NOT_PRESENT, uiConstraint.getServicePropertyName()));
348 if (comparableConstraintsOperators.contains(uiConstraint.getConstraintOperator()) && !comparableTypes
349 .contains(componentProperty.get().getType())) {
350 return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_OPERATOR_PROVIDED, uiConstraint.getServicePropertyName(),
351 uiConstraint.getConstraintOperator()));
353 return isValidValueCheck(componentProperty.get().getType(), String.valueOf(uiConstraint.getValue()), uiConstraint.getServicePropertyName());