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,
94 final String capabilityName) {
96 if (NodeFilterConstraintAction.ADD == action || NodeFilterConstraintAction.UPDATE == action) {
97 for (final String uiConstraint : uiConstraints) {
98 final UIConstraint constraint = new ConstraintConvertor().convert(uiConstraint);
99 if (ConstraintConvertor.PROPERTY_CONSTRAINT.equals(constraint.getSourceType())) {
100 final Either<Boolean, ResponseFormat> booleanResponseFormatEither = validatePropertyConstraint(parentComponent,
101 componentInstanceId, constraint, capabilityName);
102 if (booleanResponseFormatEither.isRight()) {
103 return booleanResponseFormatEither;
106 else if (ConstraintConvertor.SERVICE_INPUT_CONSTRAINT.equals(constraint.getSourceType())) {
107 final Either<Boolean, ResponseFormat> booleanResponseFormatEither = validateInputConstraint(parentComponent,
108 componentInstanceId, constraint);
109 if (booleanResponseFormatEither.isRight()) {
110 return booleanResponseFormatEither;
113 else if (ConstraintConvertor.STATIC_CONSTRAINT.equals(constraint.getSourceType())) {
114 Either<Boolean, ResponseFormat> booleanResponseFormatEither;
115 if (NodeFilterConstraintType.PROPERTIES.equals(nodeFilterConstraintType)) {
116 booleanResponseFormatEither = isComponentPropertyFilterValid(parentComponent, componentInstanceId, constraint);
118 booleanResponseFormatEither = isComponentCapabilityPropertyFilterValid(parentComponent, componentInstanceId, constraint);
120 if (booleanResponseFormatEither.isRight()) {
121 return booleanResponseFormatEither;
126 } catch (final Exception e) {
127 LOGGER.debug("Provided constraint" + uiConstraints, e);
128 return Either.right(componentsUtils.getResponseFormat(ActionStatus.CONSTRAINT_FORMAT_INCORRECT));
130 return Either.left(true);
133 private Either<Boolean, ResponseFormat> isComponentCapabilityPropertyFilterValid(final Component parentComponent,
134 final String componentInstanceId,
135 final UIConstraint uiConstraint) {
136 return validateStaticValueAndOperatorOfCapabilityProperties(parentComponent, componentInstanceId, uiConstraint);
139 private Either<Boolean, ResponseFormat> isComponentPropertyFilterValid(Component parentComponent, String componentInstanceId,
140 UIConstraint constraint) {
141 return validateStaticValueAndOperator(parentComponent, componentInstanceId, constraint);
144 private Either<Boolean, ResponseFormat> validatePropertyConstraint(final Component parentComponent, final String componentInstanceId,
145 final UIConstraint uiConstraint, final String capabilityName) {
146 String source = SOURCE;
147 final Optional<ComponentInstance> optionalComponentInstance;
148 final List<PropertyDefinition> propertyDefinitions = parentComponent.getProperties();
149 final var SELF = "SELF";
150 List<? extends PropertyDefinition> sourcePropertyDefinition =
151 SELF.equalsIgnoreCase(uiConstraint.getSourceName()) && propertyDefinitions != null ? propertyDefinitions
152 : Collections.emptyList();
153 if (sourcePropertyDefinition.isEmpty() && !SELF.equalsIgnoreCase(uiConstraint.getSourceName())) {
154 optionalComponentInstance = parentComponent.getComponentInstances().stream()
155 .filter(componentInstance -> uiConstraint.getSourceName().equals(componentInstance.getName())).findFirst();
156 if (optionalComponentInstance.isPresent()) {
157 final List<ComponentInstanceProperty> componentInstanceProperties = parentComponent.getComponentInstancesProperties()
158 .get(optionalComponentInstance.get().getUniqueId());
159 sourcePropertyDefinition = componentInstanceProperties == null ? new ArrayList<>() : componentInstanceProperties;
162 if (CollectionUtils.isNotEmpty(sourcePropertyDefinition)) {
163 final Optional<? extends PropertyDefinition> sourceSelectedProperty = sourcePropertyDefinition.stream()
164 .filter(property -> uiConstraint.getValue().equals(property.getName())).findFirst();
165 Optional<? extends PropertyDefinition> targetComponentInstanceProperty = getProperty(parentComponent, componentInstanceId, capabilityName, uiConstraint.getServicePropertyName());
167 source = !targetComponentInstanceProperty.isPresent() ? "Target" : SOURCE;
168 if (sourceSelectedProperty.isPresent() && targetComponentInstanceProperty.isPresent()) {
169 return validatePropertyData(uiConstraint, sourceSelectedProperty, targetComponentInstanceProperty);
172 final String missingProperty = source.equals(SOURCE) ? uiConstraint.getValue().toString() : uiConstraint.getServicePropertyName();
173 return Either.right(componentsUtils.getResponseFormat(ActionStatus.MAPPED_PROPERTY_NOT_FOUND, source, missingProperty));
176 private Optional<ComponentInstanceProperty> getProperty(final Component parentComponent, final String componentInstanceId,
177 final String capabilityName, final String propertyName) {
179 if (StringUtils.isEmpty(capabilityName)) {
180 return parentComponent.getComponentInstancesProperties().get(componentInstanceId).stream()
181 .filter(property -> propertyName.equals(property.getName())).findFirst();
183 final Optional<ComponentInstance> componentInstanceOptional = parentComponent.getComponentInstances().stream()
184 .filter(componentInstance -> componentInstance.getUniqueId().equals(componentInstanceId)).findAny();
185 if (componentInstanceOptional.isPresent()) {
186 for (final List<CapabilityDefinition> listOfCaps : componentInstanceOptional.get().getCapabilities().values()) {
187 final Optional<CapabilityDefinition> capDef = listOfCaps.stream().filter(cap -> cap.getName().equals(capabilityName)).findAny();
188 if (capDef.isPresent()) {
189 return capDef.get().getProperties().stream().filter(property -> propertyName.equals(property.getName())).findFirst();
194 return Optional.empty();
197 private Either<Boolean, ResponseFormat> validateInputConstraint(final Component parentComponent, final String componentInstanceId,
198 final UIConstraint uiConstraint) {
199 final List<InputDefinition> sourceInputDefinition = parentComponent.getInputs();
200 if (CollectionUtils.isNotEmpty(sourceInputDefinition)) {
201 final Optional<? extends InputDefinition> sourceSelectedProperty = sourceInputDefinition.stream()
202 .filter(input -> uiConstraint.getValue().equals(input.getName())).findFirst();
203 final Optional<? extends PropertyDefinition> targetComponentInstanceProperty = parentComponent.getComponentInstancesProperties()
204 .get(componentInstanceId).stream().filter(property -> uiConstraint.getServicePropertyName().equals(property.getName())).findFirst();
205 if (sourceSelectedProperty.isPresent() && targetComponentInstanceProperty.isPresent()) {
206 return validatePropertyData(uiConstraint, sourceSelectedProperty, targetComponentInstanceProperty);
209 LOGGER.debug("Parent component does not have inputs", parentComponent);
210 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INPUTS_NOT_FOUND));
213 private Either<Boolean, ResponseFormat> validatePropertyData(UIConstraint uiConstraint,
214 Optional<? extends PropertyDefinition> sourceSelectedProperty,
215 Optional<? extends PropertyDefinition> targetComponentInstanceProperty) {
216 if (sourceSelectedProperty.isPresent() && targetComponentInstanceProperty.isPresent()) {
217 final PropertyDefinition sourcePropDefinition = sourceSelectedProperty.get();
218 final String sourceType = sourcePropDefinition.getType();
219 final PropertyDefinition targetPropDefinition = targetComponentInstanceProperty.get();
220 final String targetType = targetPropDefinition.getType();
221 if (sourceType.equals(targetType)) {
222 if (schemableTypes.contains(sourceType)) {
223 final SchemaDefinition sourceSchemaDefinition = sourcePropDefinition.getSchema();
224 final SchemaDefinition targetSchemaDefinition = targetPropDefinition.getSchema();
225 if (!sourceSchemaDefinition.equals(targetSchemaDefinition)) {
226 return Either.right(componentsUtils
227 .getResponseFormat(ActionStatus.SOURCE_TARGET_SCHEMA_MISMATCH, uiConstraint.getServicePropertyName(),
228 uiConstraint.getValue().toString()));
231 return Either.left(Boolean.TRUE);
233 return Either.right(componentsUtils
234 .getResponseFormat(ActionStatus.SOURCE_TARGET_PROPERTY_TYPE_MISMATCH, uiConstraint.getServicePropertyName(),
235 uiConstraint.getValue().toString()));
238 LOGGER.debug("Null value passed to `validatePropertyData` - sourceSelectedProperty: '{}' - targetComponentInstanceProperty: '{}'",
239 sourceSelectedProperty, targetComponentInstanceProperty);
240 return Either.right(componentsUtils
241 .getResponseFormat(ActionStatus.GENERAL_ERROR, uiConstraint.getServicePropertyName(), uiConstraint.getValue().toString()));
245 private Either<Boolean, ResponseFormat> validateStaticValueAndOperator(final Component parentComponent, final String componentInstanceId,
246 final UIConstraint uiConstraint) {
247 if (!(Objects.nonNull(uiConstraint) && uiConstraint.getValue() instanceof String)) {
248 return Either.left(false);
250 //TODO: get capabilities properties when constraint type is capabilities
251 final Optional<ComponentInstanceProperty> componentInstanceProperty = parentComponent.getComponentInstancesProperties()
252 .get(componentInstanceId).stream().filter(property -> uiConstraint.getServicePropertyName().equals(property.getName())).findFirst();
253 if (!componentInstanceProperty.isPresent()) {
254 return Either.right(componentsUtils.getResponseFormat(ActionStatus.SELECTED_PROPERTY_NOT_PRESENT, uiConstraint.getServicePropertyName()));
256 if (comparableConstraintsOperators.contains(uiConstraint.getConstraintOperator()) && !comparableTypes
257 .contains(componentInstanceProperty.get().getType())) {
258 return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_OPERATOR_PROVIDED, uiConstraint.getServicePropertyName(),
259 uiConstraint.getConstraintOperator()));
261 return isValidValueCheck(componentInstanceProperty.get().getType(), String.valueOf(uiConstraint.getValue()),
262 uiConstraint.getServicePropertyName());
265 private Either<Boolean, ResponseFormat> validateStaticValueAndOperatorOfCapabilityProperties(final Component parentComponent,
266 final String componentInstanceId,
267 final UIConstraint uiConstraint) {
268 if (!(Objects.nonNull(uiConstraint) && uiConstraint.getValue() instanceof String)) {
269 return Either.left(false);
271 Optional<ComponentInstanceProperty> optionalComponentInstanceProperty = Optional.empty();
272 final Optional<ComponentInstance> optionalComponentInstances = parentComponent.getComponentInstances().stream()
273 .filter(componentInstance -> componentInstanceId.equalsIgnoreCase(componentInstance.getUniqueId())).findFirst();
274 if (optionalComponentInstances.isPresent()) {
275 final Optional<List<CapabilityDefinition>> optionalCapabilityDefinitionList = optionalComponentInstances.get().getCapabilities().values()
276 .stream().filter(capabilityDefinitions -> capabilityDefinitions.stream()
277 .allMatch(capabilityDefinition -> capabilityDefinition.getProperties() != null)).collect(Collectors.toList()).stream().filter(
278 capabilityDefinitions -> capabilityDefinitions.stream().allMatch(
279 capabilityDefinition -> capabilityDefinition.getProperties().stream().anyMatch(
280 componentInstanceProperty -> uiConstraint.getServicePropertyName()
281 .equalsIgnoreCase(componentInstanceProperty.getName())))).findFirst();
282 if (optionalCapabilityDefinitionList.isPresent() && !optionalCapabilityDefinitionList.get().isEmpty()) {
283 optionalComponentInstanceProperty = getComponentInstanceProperty(optionalCapabilityDefinitionList.get().get(0), uiConstraint.getServicePropertyName());
287 if (optionalComponentInstanceProperty.isEmpty()) {
288 return Either.right(componentsUtils.getResponseFormat(ActionStatus.SELECTED_PROPERTY_NOT_PRESENT, uiConstraint.getServicePropertyName()));
290 if (comparableConstraintsOperators.contains(uiConstraint.getConstraintOperator()) && !comparableTypes
291 .contains(optionalComponentInstanceProperty.get().getType())) {
292 return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_OPERATOR_PROVIDED, uiConstraint.getServicePropertyName(),
293 uiConstraint.getConstraintOperator()));
295 return isValidValueCheck(optionalComponentInstanceProperty.get().getType(), String.valueOf(uiConstraint.getValue()),
296 uiConstraint.getServicePropertyName());
299 private Optional<ComponentInstanceProperty> getComponentInstanceProperty(CapabilityDefinition capabilityDefinition, final String propertyName){
300 return capabilityDefinition.getProperties().stream().filter(property -> property.getName().equals(propertyName)).findAny();
303 private Either<Boolean, ResponseFormat> isValidValueCheck(String type, String value, String propertyName) {
304 ToscaPropertyType toscaPropertyType = ToscaPropertyType.isValidType(type);
305 if (Objects.isNull(toscaPropertyType)) {
306 return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_PROPERTY_TYPE, type, propertyName));
308 if (toscaPropertyType.getValidator().isValid(value, null)) {
309 return Either.left(Boolean.TRUE);
311 return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_VALUE_PROVIDED, type, propertyName, value));
314 public Either<Boolean, ResponseFormat> validateComponentFilter(final Component component, final List<String> uiConstraints,
315 final NodeFilterConstraintAction action) {
317 if (NodeFilterConstraintAction.ADD == action || NodeFilterConstraintAction.UPDATE == action) {
318 for (final String uiConstraint : uiConstraints) {
319 final UIConstraint constraint = new ConstraintConvertor().convert(uiConstraint);
320 if (ConstraintConvertor.PROPERTY_CONSTRAINT.equals(constraint.getSourceType())) {
321 final Either<Boolean, ResponseFormat> booleanResponseFormatEither = validateComponentPropertyConstraint(component,
323 if (booleanResponseFormatEither.isRight()) {
324 return booleanResponseFormatEither;
326 } else if (ConstraintConvertor.STATIC_CONSTRAINT.equals(constraint.getSourceType())) {
327 final Either<Boolean, ResponseFormat> booleanResponseFormatEither = validateComponentStaticValueAndOperator(component,
329 if (booleanResponseFormatEither.isRight()) {
330 return booleanResponseFormatEither;
335 } catch (final Exception e) {
336 LOGGER.debug("Provided constraint" + uiConstraints, e);
337 return Either.right(componentsUtils.getResponseFormat(ActionStatus.CONSTRAINT_FORMAT_INCORRECT));
339 return Either.left(true);
342 private Either<Boolean, ResponseFormat> validateComponentPropertyConstraint(final Component component, final UIConstraint uiConstraint) {
343 String source = SOURCE;
344 final List<PropertyDefinition> propertyDefinitions = component.getProperties();
345 List<? extends PropertyDefinition> sourcePropertyDefinition =
346 component.getName().equals(uiConstraint.getSourceName()) && propertyDefinitions != null ? propertyDefinitions : Collections.emptyList();
347 if (CollectionUtils.isNotEmpty(sourcePropertyDefinition)) {
348 final Optional<? extends PropertyDefinition> sourceSelectedProperty = sourcePropertyDefinition.stream()
349 .filter(property -> uiConstraint.getValue().equals(property.getName())).findFirst();
350 final Optional<? extends PropertyDefinition> targetComponentProperty = component.getProperties().stream()
351 .filter(property -> uiConstraint.getServicePropertyName().equals(property.getName())).findFirst();
352 source = !targetComponentProperty.isPresent() ? "Target" : SOURCE;
353 if (sourceSelectedProperty.isPresent() && targetComponentProperty.isPresent()) {
354 return validatePropertyData(uiConstraint, sourceSelectedProperty, targetComponentProperty);
357 final String missingProperty = source.equals(SOURCE) ? uiConstraint.getValue().toString() : uiConstraint.getServicePropertyName();
358 return Either.right(componentsUtils.getResponseFormat(ActionStatus.MAPPED_PROPERTY_NOT_FOUND, source, missingProperty));
361 private Either<Boolean, ResponseFormat> validateComponentStaticValueAndOperator(final Component component, final UIConstraint uiConstraint) {
362 if (!(Objects.nonNull(uiConstraint) && uiConstraint.getValue() instanceof String)) {
363 return Either.left(false);
365 final Optional<PropertyDefinition> componentProperty = component.getProperties().stream()
366 .filter(property -> uiConstraint.getServicePropertyName().equals(property.getName())).findFirst();
367 if (componentProperty.isEmpty()) {
368 return Either.right(componentsUtils.getResponseFormat(ActionStatus.SELECTED_PROPERTY_NOT_PRESENT, uiConstraint.getServicePropertyName()));
370 if (comparableConstraintsOperators.contains(uiConstraint.getConstraintOperator()) && !comparableTypes
371 .contains(componentProperty.get().getType())) {
372 return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_OPERATOR_PROVIDED, uiConstraint.getServicePropertyName(),
373 uiConstraint.getConstraintOperator()));
375 return isValidValueCheck(componentProperty.get().getType(), String.valueOf(uiConstraint.getValue()), uiConstraint.getServicePropertyName());