From 6896c1b309aaa50dca820169b9f1ae3f8af84294 Mon Sep 17 00:00:00 2001 From: siddharth0905 Date: Wed, 10 Apr 2019 17:49:51 +0530 Subject: Apply Valid Value Constraints validation Apply Valid Value Constraints validation for FE and BE in Property Assignment, Input, Service Consumption screen Change-Id: I01c7523bad702f003cd52fd88bc69fe950b2b4f3 Issue-ID: SDC-2224 Signed-off-by: siddharth0905 --- .../sdc/be/components/impl/BaseBusinessLogic.java | 91 ++++- .../be/components/impl/ComponentBusinessLogic.java | 40 ++- .../impl/ComponentInstanceBusinessLogic.java | 85 +++-- .../be/components/impl/InputsBusinessLogic.java | 58 +++- .../impl/InterfaceOperationBusinessLogic.java | 21 ++ .../be/components/impl/ResourceBusinessLogic.java | 107 +++--- .../be/components/impl/ServiceBusinessLogic.java | 108 +++++- .../property/DefaultPropertyDeclarator.java | 11 +- .../PropertyValueConstraintValidationUtil.java | 374 +++++++++++++++++++++ .../sdc/be/servlets/ComponentPropertyServlet.java | 38 ++- .../sdc/be/servlets/ServiceConsumptionServlet.java | 87 ++--- 11 files changed, 853 insertions(+), 167 deletions(-) create mode 100644 catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtil.java (limited to 'catalog-be/src/main/java') diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/BaseBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/BaseBusinessLogic.java index 8ee1864862..65f1e4981a 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/BaseBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/BaseBusinessLogic.java @@ -21,7 +21,17 @@ package org.openecomp.sdc.be.components.impl; import com.google.gson.JsonElement; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + import fj.data.Either; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.openecomp.sdc.be.components.impl.exceptions.ComponentException; import org.openecomp.sdc.be.components.validation.UserValidations; @@ -37,19 +47,33 @@ import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.impl.ComponentsUtils; -import org.openecomp.sdc.be.model.*; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.IComplexDefaultValue; +import org.openecomp.sdc.be.model.IPropertyInputCommon; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.PropertyConstraint; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache; import org.openecomp.sdc.be.model.jsontitan.operations.ArtifactsOperations; import org.openecomp.sdc.be.model.jsontitan.operations.InterfaceOperation; import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; import org.openecomp.sdc.be.model.operations.StorageException; -import org.openecomp.sdc.be.model.operations.api.*; +import org.openecomp.sdc.be.model.operations.api.IElementOperation; +import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation; +import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation; +import org.openecomp.sdc.be.model.operations.api.IGroupOperation; +import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation; import org.openecomp.sdc.be.model.operations.impl.PolicyTypeOperation; import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; +import org.openecomp.sdc.be.model.tosca.ToscaType; import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter; import org.openecomp.sdc.be.model.tosca.validators.DataTypeValidatorConverter; import org.openecomp.sdc.be.model.tosca.validators.PropertyTypeValidator; @@ -61,11 +85,6 @@ import org.openecomp.sdc.common.log.wrappers.Logger; import org.openecomp.sdc.exception.ResponseFormat; import org.springframework.beans.factory.annotation.Autowired; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - public abstract class BaseBusinessLogic { private static final String FAILED_TO_LOCK_COMPONENT_ERROR = "Failed to lock component {} error - {}"; @@ -374,7 +393,6 @@ public abstract class BaseBusinessLogic { ComponentTypeEnum getComponentTypeByParentComponentType(ComponentTypeEnum parentComponentType) { switch (parentComponentType) { case SERVICE: - return ComponentTypeEnum.RESOURCE; case RESOURCE: return ComponentTypeEnum.RESOURCE; case PRODUCT: @@ -666,8 +684,63 @@ public abstract class BaseBusinessLogic { return jsonElement.toString(); } - protected void rollbackWithException(ActionStatus actionStatus, String... params) { + void rollbackWithException(ActionStatus actionStatus, String... params) { titanDao.rollback(); throw new ComponentException(actionStatus, params); } + + public List setInputConstraint(T inputDefinition) { + if (StringUtils.isNotBlank(inputDefinition.getParentPropertyType()) + && StringUtils.isNotBlank(inputDefinition.getSubPropertyInputPath())) { + return setConstraint(inputDefinition); + } + + return Collections.emptyList(); + } + + private List setConstraint(T inputDefinition) { + List constraints = new ArrayList<>(); + String[] inputPathArr = inputDefinition.getSubPropertyInputPath().split("#"); + if (inputPathArr.length > 1) { + inputPathArr = ArrayUtils.remove(inputPathArr, 0); + } + + Map dataTypeDefinitionMap = + applicationDataTypeCache.getAll().left().value(); + + String propertyType = inputDefinition.getParentPropertyType(); + + for (String anInputPathArr : inputPathArr) { + if (ToscaType.isPrimitiveType(propertyType)) { + constraints.addAll( + dataTypeDefinitionMap.get(propertyType).getConstraints()); + } else if (!ToscaType.isCollectionType(propertyType)) { + propertyType = setConstraintForComplexType(dataTypeDefinitionMap, propertyType, anInputPathArr, + constraints); + } + } + + return constraints; + } + + private String setConstraintForComplexType(Map dataTypeDefinitionMap, + String propertyType, + String anInputPathArr, + List constraints) { + String type = null; + List propertyDefinitions = + dataTypeDefinitionMap.get(propertyType).getProperties(); + for (PropertyDefinition propertyDefinition : propertyDefinitions) { + if (propertyDefinition.getName().equals(anInputPathArr)) { + if (ToscaType.isPrimitiveType(propertyDefinition.getType())) { + constraints.addAll(propertyDefinition.getConstraints()); + } else { + type = propertyDefinition.getType(); + } + break; + } + } + + return type; + } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentBusinessLogic.java index 6b17d1c8e9..acf28c2455 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentBusinessLogic.java @@ -20,6 +20,13 @@ package org.openecomp.sdc.be.components.impl; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; + import fj.data.Either; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -34,9 +41,28 @@ import org.openecomp.sdc.be.dao.utils.MapUtil; import org.openecomp.sdc.be.datamodel.api.HighestFilterEnum; import org.openecomp.sdc.be.datatypes.components.ServiceMetadataDataDefinition; import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; -import org.openecomp.sdc.be.datatypes.enums.*; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition; -import org.openecomp.sdc.be.model.*; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.CapReqDef; +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.ComponentParametersView; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.GroupDefinition; +import org.openecomp.sdc.be.model.IComponentInstanceConnectedElement; +import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Operation; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.cache.ComponentCache; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; @@ -54,13 +80,6 @@ import org.openecomp.sdc.common.util.ValidationUtils; import org.openecomp.sdc.exception.ResponseFormat; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Collectors; - public abstract class ComponentBusinessLogic extends BaseBusinessLogic { @Autowired @@ -72,6 +91,9 @@ public abstract class ComponentBusinessLogic extends BaseBusinessLogic { @Autowired private GenericTypeBusinessLogic genericTypeBusinessLogic; + @Autowired + private ComponentInstanceBusinessLogic componentInstanceBusinessLogic; + public void setGenericTypeBusinessLogic(GenericTypeBusinessLogic genericTypeBusinessLogic) { this.genericTypeBusinessLogic = genericTypeBusinessLogic; } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java index 1eb50e846a..0c6735f8c1 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java @@ -20,7 +20,26 @@ package org.openecomp.sdc.be.components.impl; +import static org.openecomp.sdc.be.components.property.GetInputUtils.isGetInputValueForInput; + import com.google.common.collect.Sets; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.function.BiConsumer; +import java.util.stream.Collectors; + import fj.data.Either; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; @@ -38,41 +57,43 @@ import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum; import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil; import org.openecomp.sdc.be.datatypes.elements.CINodeFilterDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ForwardingPathDataDefinition; import org.openecomp.sdc.be.datatypes.elements.GetInputValueDataDefinition; import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition; -import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition; import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; -import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; import org.openecomp.sdc.be.impl.ForwardingPathUtils; import org.openecomp.sdc.be.impl.ServiceFilterUtils; import org.openecomp.sdc.be.info.CreateAndAssotiateInfo; -import org.openecomp.sdc.be.model.Component; -import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.ArtifactDefinition; import org.openecomp.sdc.be.model.CapabilityDefinition; -import org.openecomp.sdc.be.model.InterfaceDefinition; -import org.openecomp.sdc.be.model.RequirementDefinition; -import org.openecomp.sdc.be.model.Resource; -import org.openecomp.sdc.be.model.Service; -import org.openecomp.sdc.be.model.User; +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.ComponentInstancePropInput; -import org.openecomp.sdc.be.model.LifecycleStateEnum; -import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.ComponentParametersView; import org.openecomp.sdc.be.model.DataTypeDefinition; -import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.GroupDefinition; import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition.PropertyNames; import org.openecomp.sdc.be.model.RelationshipInfo; import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; -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.PropertyDefinition.PropertyNames; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache; import org.openecomp.sdc.be.model.jsontitan.operations.ForwardingPathOperation; import org.openecomp.sdc.be.model.jsontitan.operations.NodeFilterOperation; import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; @@ -95,24 +116,6 @@ import org.openecomp.sdc.common.util.ValidationUtils; import org.openecomp.sdc.exception.ResponseFormat; import org.springframework.beans.factory.annotation.Autowired; -import java.util.Arrays; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; -import java.util.function.BiConsumer; -import java.util.stream.Collectors; - -import static org.openecomp.sdc.be.components.property.GetInputUtils.isGetInputValueForInput; - @org.springframework.stereotype.Component public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { @@ -131,6 +134,9 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { public static final String FAILED_TO_COPY_COMP_INSTANCE_TO_CANVAS = "Failed to copy the component instance to the canvas"; public static final String COPY_COMPONENT_INSTANCE_OK = "Copy component instance OK"; + @Autowired + private ApplicationDataTypeCache applicationDataTypeCache; + @Autowired private IComponentInstanceOperation componentInstanceOperation; @@ -1673,6 +1679,17 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); return resultOp; } + + //Validate value and Constraint of property + Either constraintValidatorResponse = + PropertyValueConstraintValidationUtil.getInstance(). + validatePropertyConstraints(properties, applicationDataTypeCache); + if (constraintValidatorResponse.isRight()) { + log.error("Failed validation value and constraint of property: {}", + constraintValidatorResponse.right().value()); + return Either.right(constraintValidatorResponse.right().value()); + } + Either resourceInstanceStatus = getResourceInstanceById(containerComponent, resourceInstanceId); if (resourceInstanceStatus.isRight()) { resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_INSTANCE_NOT_FOUND_ON_SERVICE, resourceInstanceId, componentId)); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java index 357eb14ed0..f3b1b14652 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java @@ -24,15 +24,20 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; import fj.data.Either; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.ListUtils; +import org.apache.commons.collections4.MapUtils; import org.openecomp.sdc.be.components.property.PropertyDeclarationOrchestrator; import org.openecomp.sdc.be.components.validation.ComponentValidations; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; import org.openecomp.sdc.be.dao.utils.MapUtil; +import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil; import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; @@ -44,12 +49,15 @@ import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.ComponentParametersView; 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.cache.ApplicationDataTypeCache; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter; import org.openecomp.sdc.common.log.wrappers.Logger; import org.openecomp.sdc.exception.ResponseFormat; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.inject.Inject; @@ -71,7 +79,6 @@ public class InputsBusinessLogic extends BaseBusinessLogic { private PropertyDeclarationOrchestrator propertyDeclarationOrchestrator; @Inject private ComponentInstanceBusinessLogic componentInstanceBusinessLogic; - /** * associate inputs to a given component with paging * @@ -124,7 +131,13 @@ public class InputsBusinessLogic extends BaseBusinessLogic { log.debug("Failed to found component instance inputs {}, error: {}", componentInstanceId, actionStatus); return Either.right(componentsUtils.getResponseFormat(actionStatus)); } - Map> ciInputs = Optional.ofNullable(component.getComponentInstancesInputs()).orElse(Collections.emptyMap()); + Map> ciInputs = + Optional.ofNullable(component.getComponentInstancesInputs()).orElse(Collections.emptyMap()); + + // Set Constraints on Input + MapUtils.emptyIfNull(ciInputs).values() + .forEach(inputs -> ListUtils.emptyIfNull(inputs) + .forEach(input -> input.setConstraints(setInputConstraint(input)))); return Either.left(ciInputs.getOrDefault(componentInstanceId, Collections.emptyList())); } @@ -140,7 +153,7 @@ public class InputsBusinessLogic extends BaseBusinessLogic { public Either, ResponseFormat> getComponentInstancePropertiesByInputId(String userId, String componentId, String instanceId, String inputId) { validateUserExists(userId, GET_PROPERTIES_BY_INPUT, false); String parentId = componentId; - org.openecomp.sdc.be.model.Component component = null; + org.openecomp.sdc.be.model.Component component; ComponentParametersView filters = new ComponentParametersView(); filters.disableAll(); filters.setIgnoreComponentInstances(false); @@ -246,6 +259,9 @@ public class InputsBusinessLogic extends BaseBusinessLogic { componentParametersView.disableAll(); componentParametersView.setIgnoreInputs(false); componentParametersView.setIgnoreUsers(false); + componentParametersView.setIgnoreProperties(false); + componentParametersView.setIgnoreComponentInstancesProperties(false); + componentParametersView.setIgnoreComponentInstances(false); Either validateComponent = validateComponentExists(componentId, componentType, componentParametersView); @@ -269,6 +285,14 @@ public class InputsBusinessLogic extends BaseBusinessLogic { return result; } + //Validate value and Constraint of input + Either constraintValidatorResponse = validateInputValueConstraint(component, inputs); + if (constraintValidatorResponse.isRight()) { + log.error("Failed validation value and constraint of property: {}", + constraintValidatorResponse.right().value()); + return Either.right(constraintValidatorResponse.right().value()); + } + Either, ResponseFormat> allDataTypes = getAllDataTypes(applicationDataTypeCache); if (allDataTypes.isRight()) { result = Either.right(allDataTypes.right().value()); @@ -321,6 +345,29 @@ public class InputsBusinessLogic extends BaseBusinessLogic { } } + private Either validateInputValueConstraint( + org.openecomp.sdc.be.model.Component component, List inputs) { + PropertyValueConstraintValidationUtil propertyValueConstraintValidationUtil = + PropertyValueConstraintValidationUtil.getInstance(); + List inputDefinitions = new ArrayList<>(); + for (InputDefinition inputDefinition : inputs) { + InputDefinition inputDef = new InputDefinition(); + inputDefinition.setDefaultValue(inputDefinition.getDefaultValue()); + inputDefinition.setInputPath(inputDefinition.getSubPropertyInputPath()); + inputDefinition.setType(inputDefinition.getType()); + if (Objects.nonNull(inputDefinition.getParentPropertyType())) { + ComponentInstanceProperty propertyDefinition = new ComponentInstanceProperty(); + propertyDefinition.setType(inputDefinition.getParentPropertyType()); + + inputDefinition.setProperties(Collections.singletonList(propertyDefinition)); + } + + inputDefinitions.add(inputDef); + } + + return propertyValueConstraintValidationUtil.validatePropertyConstraints(inputDefinitions, applicationDataTypeCache); + } + public Either, ResponseFormat> getInputsForComponentInput(String userId, String componentId, String inputId) { validateUserExists(userId, GET_PROPERTIES_BY_INPUT, false); org.openecomp.sdc.be.model.Component component = null; @@ -396,7 +443,7 @@ public class InputsBusinessLogic extends BaseBusinessLogic { .left() .bind(inputsToCreate -> prepareInputsForCreation(userId, componentId, inputsToCreate)) .right() - .map(err -> componentsUtils.getResponseFormat(err)); + .map(componentsUtils::getResponseFormat); return result; @@ -422,6 +469,9 @@ public class InputsBusinessLogic extends BaseBusinessLogic { private Either, StorageOperationStatus> prepareInputsForCreation(String userId, String cmptId, List inputsToCreate) { Map inputsToPersist = MapUtil.toMap(inputsToCreate, InputDefinition::getName); assignOwnerIdToInputs(userId, inputsToPersist); + inputsToPersist.values() + .forEach(input -> input.setConstraints(componentInstanceBusinessLogic.setInputConstraint(input))); + return toscaOperationFacade.addInputsToComponent(inputsToPersist, cmptId) .left() .map(persistedInputs -> inputsToCreate); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceOperationBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceOperationBusinessLogic.java index 7f19e824e5..de2839f653 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceOperationBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceOperationBusinessLogic.java @@ -450,6 +450,8 @@ public class InterfaceOperationBusinessLogic extends BaseBusinessLogic { operationInput.setToscaDefaultValue(getInputToscaDefaultValue(operationInput, component)); operationInput.setValue(componentInput.getValue()); operationInput.setSchema(componentInput.getSchema()); + operationInput.setParentPropertyType(componentInput.getParentPropertyType()); + operationInput.setSubPropertyInputPath(componentInput.getSubPropertyInputPath()); } //Set the tosca default value for inputs mapped to component inputs as well as other outputs operationInput.setToscaDefaultValue(getInputToscaDefaultValue(operationInput, component)); @@ -460,6 +462,7 @@ public class InterfaceOperationBusinessLogic extends BaseBusinessLogic { Map> defaultInputValue; if (isOperationInputMappedToComponentInput(input, component.getInputs())) { String propertyName = input.getInputId().substring(input.getInputId().indexOf('.') + 1); + setParentPropertyTypeAndInputPath(input, component); defaultInputValue = createMappedInputPropertyDefaultValue(propertyName); } else { //Currently inputs can only be mapped to a declared input or an other operation outputs @@ -468,6 +471,24 @@ public class InterfaceOperationBusinessLogic extends BaseBusinessLogic { return new Gson().toJson(defaultInputValue); } + private void setParentPropertyTypeAndInputPath(OperationInputDefinition input, + org.openecomp.sdc.be.model.Component component) { + if (CollectionUtils.isEmpty(component.getInputs())) { + return; + } + + component.getInputs() + .stream() + .filter(inp -> inp.getUniqueId().equals( + input.getInputId().substring(0, input.getInputId().lastIndexOf('.')))) + .forEach(inp -> { + input.setParentPropertyType(inp.getParentPropertyType()); + if (Objects.nonNull(input.getName())) { + input.setSubPropertyInputPath(input.getName().replaceAll("\\.", "#")); + } + }); + } + private void addOperationToInterface(InterfaceDefinition interfaceDefinition, Operation interfaceOperation) { interfaceOperation.setUniqueId(UUID.randomUUID().toString()); interfaceOperation.setImplementation(createArtifactDefinition(UUID.randomUUID().toString())); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java index 92d26a4eb8..53ed2a4306 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java @@ -8,7 +8,7 @@ * 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 + * http://www.apache.org/licenses/LICENSE-2.0getUiComponentDataTransferByComponentId * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -21,10 +21,37 @@ package org.openecomp.sdc.be.components.impl; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; +import static java.util.stream.Collectors.toSet; +import static org.apache.commons.collections.CollectionUtils.isNotEmpty; +import static org.apache.commons.collections.MapUtils.isEmpty; +import static org.apache.commons.collections.MapUtils.isNotEmpty; +import static org.openecomp.sdc.be.components.impl.ImportUtils.findFirstToscaStringElement; +import static org.openecomp.sdc.be.components.impl.ImportUtils.getPropertyJsonStringValue; +import static org.openecomp.sdc.be.tosca.CsarUtils.VF_NODE_TYPE_ARTIFACTS_PATH_PATTERN; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.regex.Pattern; + import fj.data.Either; import org.apache.commons.codec.binary.Base64; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; +import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.openecomp.sdc.be.components.csar.CsarArtifactsAndGroupsBusinessLogic; @@ -53,6 +80,7 @@ import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition; import org.openecomp.sdc.be.datatypes.elements.GetInputValueDataDefinition; import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentFieldsEnum; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.CreatedFrom; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; @@ -130,31 +158,6 @@ import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; import javax.servlet.ServletContext; -import java.util.ArrayList; -import java.util.Collection; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.regex.Pattern; - -import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toList; -import static java.util.stream.Collectors.toMap; -import static java.util.stream.Collectors.toSet; -import static org.apache.commons.collections.CollectionUtils.isNotEmpty; -import static org.apache.commons.collections.MapUtils.isEmpty; -import static org.apache.commons.collections.MapUtils.isNotEmpty; -import static org.openecomp.sdc.be.components.impl.ImportUtils.findFirstToscaStringElement; -import static org.openecomp.sdc.be.components.impl.ImportUtils.getPropertyJsonStringValue; -import static org.openecomp.sdc.be.tosca.CsarUtils.VF_NODE_TYPE_ARTIFACTS_PATH_PATTERN; @org.springframework.stereotype.Component("resourceBusinessLogic") public class ResourceBusinessLogic extends ComponentBusinessLogic { @@ -5207,28 +5210,36 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { } @Override - public Either getUiComponentDataTransferByComponentId(String resourceId, List dataParamsToReturn) { - - ComponentParametersView paramsToRetuen = new ComponentParametersView(dataParamsToReturn); - Either resourceResultEither = toscaOperationFacade.getToscaElement(resourceId, - paramsToRetuen); - - if (resourceResultEither.isRight()) { - if (resourceResultEither.right().value().equals(StorageOperationStatus.NOT_FOUND)) { - log.debug("Failed to found resource with id {} ", resourceId); - Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, resourceId)); - } - - log.debug("failed to get resource by id {} with filters {}", resourceId, dataParamsToReturn); - return Either.right(componentsUtils.getResponseFormatByResource( - componentsUtils.convertFromStorageResponse(resourceResultEither.right().value()), "")); - } - - Resource resource = resourceResultEither.left().value(); - UiComponentDataTransfer dataTransfer = uiComponentDataConverter.getUiDataTransferFromResourceByParams(resource, - dataParamsToReturn); - return Either.left(dataTransfer); - } + public Either getUiComponentDataTransferByComponentId(String resourceId, + List dataParamsToReturn) { + + ComponentParametersView paramsToRetuen = new ComponentParametersView(dataParamsToReturn); + Either resourceResultEither = + toscaOperationFacade.getToscaElement(resourceId, + paramsToRetuen); + + if (resourceResultEither.isRight()) { + if (resourceResultEither.right().value().equals(StorageOperationStatus.NOT_FOUND)) { + log.debug("Failed to found resource with id {} ", resourceId); + Either + .right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, resourceId)); + } + + log.debug("failed to get resource by id {} with filters {}", resourceId, dataParamsToReturn); + return Either.right(componentsUtils.getResponseFormatByResource( + componentsUtils.convertFromStorageResponse(resourceResultEither.right().value()), "")); + } + + Resource resource = resourceResultEither.left().value(); + if (dataParamsToReturn.contains(ComponentFieldsEnum.INPUTS.getValue())) { + ListUtils.emptyIfNull(resource.getInputs()) + .forEach(input -> input.setConstraints(setInputConstraint(input))); + } + + UiComponentDataTransfer dataTransfer = uiComponentDataConverter.getUiDataTransferFromResourceByParams(resource, + dataParamsToReturn); + return Either.left(dataTransfer); + } @Override public Either shouldUpgradeToLatestDerived(Component clonedComponent) { diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java index ba3b8dfc45..364b007ce3 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java @@ -20,13 +20,39 @@ package org.openecomp.sdc.be.components.impl; +import static org.apache.commons.collections.CollectionUtils.isEmpty; +import static org.apache.commons.collections.CollectionUtils.isNotEmpty; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.getOperationOutputName; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.isOperationInputMappedToOtherOperationOutput; +import static org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum.UPDATE_SERVICE_METADATA; +import static org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.SELF; +import static org.openecomp.sdc.be.types.ServiceConsumptionSource.SERVICE_INPUT; +import static org.openecomp.sdc.be.types.ServiceConsumptionSource.STATIC; + import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import com.google.gson.Gson; import com.google.gson.GsonBuilder; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.function.Function; +import java.util.stream.Collectors; + import fj.data.Either; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; +import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.openecomp.sdc.be.components.distribution.engine.IDistributionEngine; @@ -46,6 +72,7 @@ import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.cassandra.AuditCassandraDao; import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum; import org.openecomp.sdc.be.datamodel.ServiceRelations; +import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil; import org.openecomp.sdc.be.datamodel.utils.UiComponentDataConverter; import org.openecomp.sdc.be.datatypes.elements.CINodeFilterDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ForwardingPathDataDefinition; @@ -54,6 +81,7 @@ import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationOutputDefinition; import org.openecomp.sdc.be.datatypes.elements.RequirementNodeFilterPropertyDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentFieldsEnum; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.InstantiationTypes; import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; @@ -62,7 +90,24 @@ import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; import org.openecomp.sdc.be.externalapi.servlet.representation.ServiceDistributionReqInfo; import org.openecomp.sdc.be.impl.ForwardingPathUtils; import org.openecomp.sdc.be.impl.WebAppContextWrapper; -import org.openecomp.sdc.be.model.*; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceInterface; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.DistributionStatusEnum; +import org.openecomp.sdc.be.model.DistributionTransitionEnum; +import org.openecomp.sdc.be.model.GroupInstance; +import org.openecomp.sdc.be.model.GroupInstanceProperty; +import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Operation; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.category.CategoryDefinition; import org.openecomp.sdc.be.model.jsontitan.operations.ForwardingPathOperation; import org.openecomp.sdc.be.model.jsontitan.operations.NodeFilterOperation; @@ -77,7 +122,11 @@ import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; import org.openecomp.sdc.be.model.tosca.validators.PropertyTypeValidator; import org.openecomp.sdc.be.resources.data.ComponentInstanceData; import org.openecomp.sdc.be.resources.data.ComponentMetadataData; -import org.openecomp.sdc.be.resources.data.auditing.*; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.resources.data.auditing.AuditingGenericEvent; +import org.openecomp.sdc.be.resources.data.auditing.DistributionDeployEvent; +import org.openecomp.sdc.be.resources.data.auditing.DistributionNotificationEvent; +import org.openecomp.sdc.be.resources.data.auditing.ResourceAdminEvent; import org.openecomp.sdc.be.resources.data.auditing.model.ResourceCommonInfo; import org.openecomp.sdc.be.resources.data.auditing.model.ResourceVersionInfo; import org.openecomp.sdc.be.types.ServiceConsumptionData; @@ -100,20 +149,6 @@ import org.springframework.web.context.WebApplicationContext; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.Callable; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static org.apache.commons.collections.CollectionUtils.isEmpty; -import static org.apache.commons.collections.CollectionUtils.isNotEmpty; -import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.getOperationOutputName; -import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.isOperationInputMappedToOtherOperationOutput; -import static org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum.UPDATE_SERVICE_METADATA; -import static org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.SELF; -import static org.openecomp.sdc.be.types.ServiceConsumptionSource.SERVICE_INPUT; -import static org.openecomp.sdc.be.types.ServiceConsumptionSource.STATIC; @org.springframework.stereotype.Component("serviceBusinessLogic") public class ServiceBusinessLogic extends ComponentBusinessLogic { @@ -365,7 +400,6 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic { } OperationInputDefinition operationInputDefinition = inputCandidate.get(); - // add data to operation if(Objects.nonNull(serviceConsumptionData.getValue())) { @@ -441,6 +475,14 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic { ServiceConsumptionSource sourceValue = ServiceConsumptionSource.getSourceValue(source); if(STATIC.equals(sourceValue)) { + // Validate constraint on input value + /*Either constraintValidationResult = + validateOperationInputConstraint(operationInputDefinition, serviceConsumptionData); + + if (constraintValidationResult.isRight()) { + return Either.right(constraintValidationResult.right().value()); + }*/ + return handleConsumptionStaticValue(consumptionValue, type, operation, operationInputDefinition); } @@ -612,12 +654,37 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic { return Either.right(componentsUtils.getResponseFormat( ActionStatus.INVALID_CONSUMPTION_TYPE, type)); } + + //Validate Constraint and Value + Either constraintValidationResponse = + validateOperationInputConstraint(operationInputDefinition, value, type); + if(constraintValidationResponse.isRight()) { + return Either.right(constraintValidationResponse.right().value()); + } + addStaticValueToInputOperation(value, operation, operationInputDefinition); return Either.left(operation); } - private void addStaticValueToInputOperation(String value, Operation operation, + private Either validateOperationInputConstraint( + OperationInputDefinition operationInputDefinition, String value, String type) { + ComponentInstanceProperty propertyDefinition = new ComponentInstanceProperty(); + propertyDefinition.setType(operationInputDefinition.getParentPropertyType()); + + InputDefinition inputDefinition = new InputDefinition(); + inputDefinition.setDefaultValue(value); + inputDefinition.setInputPath(operationInputDefinition.getSubPropertyInputPath()); + inputDefinition.setType(type); + if (Objects.nonNull(operationInputDefinition.getParentPropertyType())) { + inputDefinition.setProperties(Collections.singletonList(propertyDefinition)); + } + + return PropertyValueConstraintValidationUtil.getInstance() + .validatePropertyConstraints(Collections.singletonList(inputDefinition), applicationDataTypeCache); + } + + private void addStaticValueToInputOperation(String value, Operation operation, OperationInputDefinition operationInputDefinition) { operation.getInputs().delete(operationInputDefinition); operationInputDefinition.setSource(STATIC.getSource()); @@ -2571,6 +2638,11 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic { } Service service = serviceResultEither.left().value(); + if (dataParamsToReturn.contains(ComponentFieldsEnum.INPUTS.getValue())) { + ListUtils.emptyIfNull(service.getInputs()) + .forEach(input -> input.setConstraints(setInputConstraint(input))); + } + UiComponentDataTransfer dataTransfer = uiComponentDataConverter.getUiDataTransferFromServiceByParams(service, dataParamsToReturn); return Either.left(dataTransfer); } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java index bd7a58c48a..0f76210a1a 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java @@ -156,6 +156,14 @@ public abstract class DefaultPropertyDeclarator dataTypeDefinitionCache; + private static final Logger logger = LoggerFactory.getLogger(PropertyValueConstraintValidationUtil.class); + private ObjectMapper objectMapper = new ObjectMapper(); + private List errorMessages = new ArrayList<>(); + private StringBuilder completePropertyName; + private String completeInputName; + private static final String IGNORE_PROPERTY_VALUE_START_WITH = "{\"get_input\":"; + + public static PropertyValueConstraintValidationUtil getInstance() { + return new PropertyValueConstraintValidationUtil(); + } + + public Either validatePropertyConstraints( + Collection propertyDefinitionList, + ApplicationDataTypeCache applicationDataTypeCache) { + ResponseFormatManager responseFormatManager = getResponseFormatManager(); + dataTypeDefinitionCache = applicationDataTypeCache.getAll().left().value(); + CollectionUtils.emptyIfNull(propertyDefinitionList).stream() + .filter(this::isValuePresent) + .forEach(this::evaluatePropertyTypeForConstraintValidation); + + if (CollectionUtils.isNotEmpty(errorMessages)) { + logger.error("Properties with Invalid Data:", errorMessages); + ResponseFormat inputResponse = responseFormatManager.getResponseFormat(ActionStatus + .INVALID_PROPERTY_VALUES, String.join(",", errorMessages)); + return Either.right(inputResponse); + } + + return Either.left(Boolean.TRUE); + } + + private boolean isValuePresent(PropertyDefinition propertyDefinition) { + if (propertyDefinition instanceof InputDefinition) { + return StringUtils.isNotEmpty(propertyDefinition.getDefaultValue()); + } + + return StringUtils.isNotEmpty(propertyDefinition.getValue()); + } + + private void evaluatePropertyTypeForConstraintValidation(PropertyDefinition propertyDefinition) { + if (Objects.nonNull(propertyDefinition.getType()) + && dataTypeDefinitionCache.containsKey(propertyDefinition.getType())) { + + completeInputName = ""; + completePropertyName = new StringBuilder(); + if (propertyDefinition instanceof InputDefinition) { + completeInputName = propertyDefinition.getName(); + propertyDefinition = getPropertyDefinitionObjectFromInputs(propertyDefinition); + } + + if (Objects.nonNull(propertyDefinition)) { + if (ToscaType.isPrimitiveType(propertyDefinition.getType())) { + propertyDefinition.setConstraints( + org.openecomp.sdc.be.dao.utils.CollectionUtils.merge(propertyDefinition.getConstraints(), + dataTypeDefinitionCache.get(propertyDefinition.getType()).getConstraints())); + evaluateConstraintsOnProperty(propertyDefinition); + } else if (ToscaType.isCollectionType(propertyDefinition.getType())) { + propertyDefinition.setConstraints( + org.openecomp.sdc.be.dao.utils.CollectionUtils.merge(propertyDefinition.getConstraints(), + dataTypeDefinitionCache.get(propertyDefinition.getType()).getConstraints())); + evaluateConstraintsOnProperty(propertyDefinition); + evaluateCollectionTypeProperties(propertyDefinition); + } else { + setCompletePropertyName(propertyDefinition); + evaluateComplexTypeProperties(propertyDefinition); + } + } + } else { + errorMessages.add("\nUnsupported datatype found for property " + getCompletePropertyName(propertyDefinition)); + } + } + + private void setCompletePropertyName(PropertyDefinition propertyDefinition) { + if(StringUtils.isNotBlank(propertyDefinition.getUniqueId())) { + completePropertyName.append( + propertyDefinition.getUniqueId().substring(propertyDefinition.getUniqueId().lastIndexOf('.') + 1)); + } + } + + private void evaluateConstraintsOnProperty(PropertyDefinition propertyDefinition) { + ToscaType toscaType = ToscaType.isValidType(propertyDefinition.getType()); + if (isPropertyNotMappedAsInput(propertyDefinition) + && CollectionUtils.isNotEmpty(propertyDefinition.getConstraints()) + && isValidValueConstraintPresent(propertyDefinition.getConstraints())) { + for (PropertyConstraint propertyConstraint : propertyDefinition.getConstraints()) { + try { + propertyConstraint.initialize(toscaType); + propertyConstraint.validate(toscaType, propertyDefinition.getValue()); + } catch (ConstraintValueDoNotMatchPropertyTypeException | ConstraintViolationException exception) { + errorMessages.add("\n" + propertyConstraint.getErrorMessage( + toscaType, exception, getCompletePropertyName(propertyDefinition))); + } + } + } else if (isPropertyNotMappedAsInput(propertyDefinition) + && ToscaType.isPrimitiveType(propertyDefinition.getType()) + && !toscaType.isValidValue(propertyDefinition.getValue())) { + errorMessages.add(String.format("\nUnsupported value provided for %s property supported value " + + "type is %s.", getCompletePropertyName(propertyDefinition), toscaType.getType())); + } + } + + private boolean isPropertyNotMappedAsInput(PropertyDefinition propertyDefinition) { + return !propertyDefinition.getValue().startsWith(IGNORE_PROPERTY_VALUE_START_WITH); + } + + private void checkAndEvaluatePrimitiveProperty(PropertyDefinition propertyDefinition, + DataTypeDefinition dataTypeDefinition) { + if (ToscaType.isPrimitiveType(dataTypeDefinition.getName()) + && CollectionUtils.isNotEmpty(dataTypeDefinition.getConstraints())) { + + PropertyDefinition definition = new PropertyDefinition(); + definition.setValue(propertyDefinition.getValue()); + definition.setType(dataTypeDefinition.getName()); + definition.setConstraints(dataTypeDefinition.getConstraints()); + + evaluateConstraintsOnProperty(propertyDefinition); + } + } + + private void evaluateComplexTypeProperties(PropertyDefinition propertyDefinition) { + List propertyDefinitions = + dataTypeDefinitionCache.get(propertyDefinition.getType()).getProperties(); + try { + Map valueMap = + MapUtils.emptyIfNull(ConstraintUtil.parseToCollection(propertyDefinition.getValue(), + new TypeReference>() {})); + + if (CollectionUtils.isEmpty(propertyDefinitions)) { + checkAndEvaluatePrimitiveProperty(propertyDefinition, + dataTypeDefinitionCache.get(propertyDefinition.getType())); + } else { + ListUtils.emptyIfNull(propertyDefinitions) + .forEach(prop -> evaluateRegularComplexType(propertyDefinition, prop, valueMap)); + } + } catch (ConstraintValueDoNotMatchPropertyTypeException e) { + logger.debug(e.getMessage(), e); + errorMessages.add(String.format(VALUE_PROVIDED_IN_INVALID_FORMAT_FOR_PROPERTY, + getCompletePropertyName(propertyDefinition))); + } + } + + private void evaluateRegularComplexType(PropertyDefinition propertyDefinition, + PropertyDefinition prop, + Map valueMap) { + try { + if (valueMap.containsKey(prop.getName())) { + if (ToscaType.isPrimitiveType(prop.getType())) { + evaluateConstraintsOnProperty(createPropertyDefinition(prop, + String.valueOf(valueMap.get(prop.getName())))); + } else if (ToscaType.isCollectionType(prop.getType())) { + + evaluateCollectionTypeProperties(createPropertyDefinition(prop, + objectMapper.writeValueAsString(valueMap.get(prop.getName())))); + } else { + completePropertyName.append(UNDERSCORE); + completePropertyName.append(prop.getName()); + evaluateComplexTypeProperties( + createPropertyDefinition(prop, objectMapper.writeValueAsString( + valueMap.get(prop.getName())))); + } + } + } catch (IOException e) { + logger.error(e.getMessage(), e); + errorMessages.add(String.format(VALUE_PROVIDED_IN_INVALID_FORMAT_FOR_PROPERTY, + getCompletePropertyName(propertyDefinition))); + } + } + + private void evaluateCollectionTypeProperties(PropertyDefinition propertyDefinition) { + ToscaType toscaPropertyType = ToscaType.isValidType(propertyDefinition.getType()); + if (ToscaType.LIST == toscaPropertyType) { + evaluateListType(propertyDefinition); + } else if (ToscaType.MAP == toscaPropertyType) { + evaluateMapType(propertyDefinition); + } + } + + private void evaluateListType(PropertyDefinition propertyDefinition) { + try { + String schemaType = propertyDefinition.getSchemaType(); + List list = ConstraintUtil.parseToCollection(propertyDefinition.getValue(), + new TypeReference>() {}); + evaluateCollectionType(propertyDefinition, list, schemaType); + } catch (ConstraintValueDoNotMatchPropertyTypeException e) { + logger.debug(e.getMessage(), e); + errorMessages.add(String.format(VALUE_PROVIDED_IN_INVALID_FORMAT_FOR_PROPERTY, + getCompletePropertyName(propertyDefinition))); + } + } + + private void evaluateMapType(PropertyDefinition propertyDefinition) { + try { + String schemaType = propertyDefinition.getSchemaType(); + Map map = ConstraintUtil.parseToCollection(propertyDefinition.getValue(), + new TypeReference>() { + }); + evaluateCollectionType(propertyDefinition, map.values(), schemaType); + } catch (ConstraintValueDoNotMatchPropertyTypeException e) { + logger.debug(e.getMessage(), e); + errorMessages.add(String.format(VALUE_PROVIDED_IN_INVALID_FORMAT_FOR_PROPERTY, + getCompletePropertyName(propertyDefinition))); + } + } + + private void evaluateCollectionPrimitiveSchemaType(PropertyDefinition propertyDefinition, + Object value, + String schemaType) { + if (Objects.nonNull(propertyDefinition.getSchema()) + && propertyDefinition.getSchema().getProperty() instanceof PropertyDefinition) { + propertyDefinition.setConstraints(((PropertyDefinition) propertyDefinition.getSchema() + .getProperty()).getConstraints()); + propertyDefinition.setValue(String.valueOf(value)); + propertyDefinition.setType(schemaType); + evaluateConstraintsOnProperty(propertyDefinition); + } + } + private void evaluateCollectionType(PropertyDefinition propertyDefinition, + Collection valueList, + String schemaType) { + for (Object value : valueList) { + try { + if (ToscaType.isPrimitiveType(schemaType)) { + evaluateCollectionPrimitiveSchemaType(propertyDefinition, value, schemaType); + } else if (ToscaType.isCollectionType(schemaType)) { + propertyDefinition.setValue(objectMapper.writeValueAsString(value)); + propertyDefinition.setType(schemaType); + evaluateCollectionTypeProperties(propertyDefinition); + } else { + propertyDefinition.setValue(objectMapper.writeValueAsString(value)); + propertyDefinition.setType(schemaType); + completePropertyName.append(UNDERSCORE); + completePropertyName.append(propertyDefinition.getName()); + evaluateComplexTypeProperties(propertyDefinition); + } + } catch (IOException e) { + logger.debug(e.getMessage(), e); + errorMessages.add(String.format(VALUE_PROVIDED_IN_INVALID_FORMAT_FOR_PROPERTY, + getCompletePropertyName(propertyDefinition))); + } + } + } + + private String getCompletePropertyName(PropertyDefinition propertyDefinition) { + return StringUtils.isNotBlank(completeInputName) ? completeInputName : + StringUtils.isBlank(completePropertyName) ? + propertyDefinition.getName() : completePropertyName + UNDERSCORE + propertyDefinition.getName(); + } + + private PropertyDefinition createPropertyDefinition(PropertyDefinition prop, String value) { + PropertyDefinition propertyDefinition = new PropertyDefinition(); + propertyDefinition.setName(prop.getName()); + propertyDefinition.setValue(value); + propertyDefinition.setType(prop.getType()); + propertyDefinition.setConstraints(prop.getConstraints()); + propertyDefinition.setSchema(prop.getSchema()); + + return propertyDefinition; + } + + private boolean isValidValueConstraintPresent(List propertyConstraints) { + return propertyConstraints.stream() + .anyMatch(propertyConstraint -> propertyConstraint instanceof ValidValuesConstraint); + } + + private PropertyDefinition getPropertyDefinitionObjectFromInputs( + PropertyDefinition property) { + InputDefinition inputDefinition = (InputDefinition) property; + PropertyDefinition propertyDefinition = null; + + if (CollectionUtils.isEmpty(inputDefinition.getProperties()) + || ToscaType.isPrimitiveType(inputDefinition.getProperties().get(0).getType())) { + propertyDefinition = new PropertyDefinition(); + propertyDefinition.setType(inputDefinition.getType()); + propertyDefinition.setValue(inputDefinition.getDefaultValue()); + propertyDefinition.setName(inputDefinition.getName()); + } else if (Objects.nonNull(inputDefinition.getInputPath())) { + propertyDefinition = evaluateComplexTypeInputs(inputDefinition); + } + + return propertyDefinition; + } + + private PropertyDefinition evaluateComplexTypeInputs(InputDefinition inputDefinition) { + Map inputMap = new HashMap<>(); + PropertyDefinition propertyDefinition = new PropertyDefinition(); + String[] inputPathArr = inputDefinition.getInputPath().split("#"); + if (inputPathArr.length > 1) { + inputPathArr = ArrayUtils.remove(inputPathArr, 0); + } + + try { + Map presentMap = inputMap; + for (int i = 0; i < inputPathArr.length ; i++) { + if (i == inputPathArr.length - 1) { + presentMap.computeIfAbsent(inputPathArr[i], k -> inputDefinition.getDefaultValue()); + } else { + presentMap.computeIfAbsent(inputPathArr[i], k -> new HashMap()); + presentMap = (Map) presentMap.get(inputPathArr[i]); + } + } + + if (CollectionUtils.isNotEmpty(inputDefinition.getProperties())) { + propertyDefinition.setType(inputDefinition.getProperties().get(0).getType()); + } + propertyDefinition.setName(inputDefinition.getName()); + propertyDefinition.setValue(objectMapper.writeValueAsString(inputMap)); + } catch (IOException e) { + logger.error(e.getMessage(), e); + errorMessages.add(String.format(VALUE_PROVIDED_IN_INVALID_FORMAT_FOR_PROPERTY, + inputDefinition.getName())); + } + + return propertyDefinition; + } + + protected ResponseFormatManager getResponseFormatManager() { + return ResponseFormatManager.getInstance(); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentPropertyServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentPropertyServlet.java index 79e63c71b5..38c04a131c 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentPropertyServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentPropertyServlet.java @@ -17,28 +17,45 @@ package org.openecomp.sdc.be.servlets; import com.jcabi.aspects.Loggable; + +import java.util.List; +import java.util.Map; + import fj.data.Either; -import io.swagger.annotations.*; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; import org.openecomp.sdc.be.components.impl.PropertyBusinessLogic; import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil; import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache; import org.openecomp.sdc.be.resources.data.EntryData; import org.openecomp.sdc.common.api.Constants; import org.openecomp.sdc.exception.ResponseFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import javax.inject.Singleton; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.*; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import java.util.List; -import java.util.Map; @Loggable(prepend = true, value = Loggable.DEBUG, trim = false) @Path("/v1/catalog") @@ -46,6 +63,9 @@ import java.util.Map; @Singleton public class ComponentPropertyServlet extends BeGenericServlet { + @Autowired + ApplicationDataTypeCache applicationDataTypeCache; + private static final Logger log = LoggerFactory.getLogger(ComponentPropertyServlet.class); private static final String CREATE_PROPERTY = "Create Property"; private static final String DEBUG_MESSAGE = "Start handle request of {} modifier id is {}"; @@ -264,6 +284,16 @@ public class ComponentPropertyServlet extends BeGenericServlet { return buildErrorResponse(responseFormat); } + //Validate value and Constraint of property + Either constraintValidatorResponse = + PropertyValueConstraintValidationUtil.getInstance(). + validatePropertyConstraints(properties.values(), applicationDataTypeCache); + if (constraintValidatorResponse.isRight()) { + log.error("Failed validation value and constraint of property: {}", + constraintValidatorResponse.right().value()); + return buildErrorResponse(constraintValidatorResponse.right().value()); + } + // update property PropertyBusinessLogic businessLogic = getPropertyBL(context); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceConsumptionServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceConsumptionServlet.java index 4ed2f95676..990e3bc356 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceConsumptionServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceConsumptionServlet.java @@ -44,6 +44,7 @@ import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.model.Operation; +import org.openecomp.sdc.be.model.OperationInput; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.tosca.ToscaFunctions; import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; @@ -158,8 +159,7 @@ public class ServiceConsumptionServlet extends BeGenericServlet { } List inputs = inputsEither.left().value(); - updateOperationInputListForUi(inputs); - return buildOkResponse(inputs); + return buildOkResponse(updateOperationInputListForUi(inputs, interfaceOperationBL)); } catch (Exception e) { BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Operation Inputs"); @@ -169,43 +169,52 @@ public class ServiceConsumptionServlet extends BeGenericServlet { } } - private void updateOperationInputListForUi(List inputsList) { - for(OperationInputDefinition input : inputsList) { - - String value = input.getValue(); - // No Additional UI mapping needed for STATIC source - if(StringUtils.isEmpty(value) - || ServiceConsumptionSource.STATIC.getSource().equals(input.getSource())) { - continue; - } - - - // Additional UI mapping needed for other sources - try { - Map valueAsMap = (new Gson()).fromJson(value, Map.class); - String toscaFunction = valueAsMap.keySet().iterator().next(); - Object consumptionValueName = valueAsMap.values().iterator().next(); - if(consumptionValueName instanceof List) { - List toscaFunctionList = (List) consumptionValueName; - String consumptionInputValue = null; - if (ToscaFunctions.GET_PROPERTY.getFunctionName().equals(toscaFunction)) { - consumptionInputValue = String.valueOf(toscaFunctionList.get(1)); - } else if (ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName().equals(toscaFunction)) { - //Return full output name - consumptionInputValue = - toscaFunctionList.get(1) + "." + toscaFunctionList.get(2) + "." +toscaFunctionList.get(3); - } - input.setValue(consumptionInputValue); - } else { - input.setValue(String.valueOf(consumptionValueName)); - } - } - catch(JsonParseException ex){ - log.info("This means it is static value for which no changes are needed"); - } - } - } - + private List updateOperationInputListForUi(List inputsList, + InterfaceOperationBusinessLogic interfaceOperationBL) { + List operationInputs = new ArrayList<>(); + for(OperationInputDefinition input : inputsList) { + + String value = input.getValue(); + + // Additional UI mapping needed for other sources + if (StringUtils.isNotBlank(value) + && !ServiceConsumptionSource.STATIC.getSource().equals(input.getSource())) { + uiMappingForOtherSources(value, input); + } + + // Add Constraint for UI + OperationInput operationInput = new OperationInput(input); + operationInput.setConstraints(interfaceOperationBL.setInputConstraint(input)); + operationInputs.add(operationInput); + } + + return operationInputs; + } + + private void uiMappingForOtherSources(String value, OperationInputDefinition input) { + try { + Map valueAsMap = (new Gson()).fromJson(value, Map.class); + String toscaFunction = valueAsMap.keySet().iterator().next(); + Object consumptionValueName = valueAsMap.values().iterator().next(); + if(consumptionValueName instanceof List) { + List toscaFunctionList = (List) consumptionValueName; + String consumptionInputValue = null; + if (ToscaFunctions.GET_PROPERTY.getFunctionName().equals(toscaFunction)) { + consumptionInputValue = String.valueOf(toscaFunctionList.get(1)); + } else if (ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName().equals(toscaFunction)) { + //Return full output name + consumptionInputValue = + toscaFunctionList.get(1) + "." + toscaFunctionList.get(2) + "." +toscaFunctionList.get(3); + } + input.setValue(consumptionInputValue); + } else { + input.setValue(String.valueOf(consumptionValueName)); + } + } + catch(JsonParseException ex){ + log.info("This means it is static value for which no changes are needed"); + } + } private Either>, ResponseFormat> getServiceConsumptionData(String data, User user) { -- cgit 1.2.3-korg