aboutsummaryrefslogtreecommitdiffstats
path: root/catalog-be/src
diff options
context:
space:
mode:
authorsiddharth0905 <siddharth.singh4@amdocs.com>2019-04-10 17:49:51 +0530
committerAvi Gaffa <avi.gaffa@amdocs.com>2019-04-11 07:11:04 +0000
commit6896c1b309aaa50dca820169b9f1ae3f8af84294 (patch)
tree8da13382863f2e4adc9724dd046b535032ae58c7 /catalog-be/src
parent4568e48647b15b5654a669651ddf536d590288b0 (diff)
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 <siddharth.singh4@amdocs.com>
Diffstat (limited to 'catalog-be/src')
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/BaseBusinessLogic.java91
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentBusinessLogic.java40
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java85
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java58
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceOperationBusinessLogic.java21
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java107
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java108
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java11
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtil.java374
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentPropertyServlet.java38
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceConsumptionServlet.java87
-rw-r--r--catalog-be/src/main/resources/config/error-configuration.yaml6
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtilTest.java317
-rw-r--r--catalog-be/src/test/resources/csars/with_groups.csarbin65804 -> 65799 bytes
-rw-r--r--catalog-be/src/test/resources/types/datatypes/constraintTest.json405
15 files changed, 1581 insertions, 167 deletions
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 <T extends PropertyDataDefinition> List<PropertyConstraint> setInputConstraint(T inputDefinition) {
+ if (StringUtils.isNotBlank(inputDefinition.getParentPropertyType())
+ && StringUtils.isNotBlank(inputDefinition.getSubPropertyInputPath())) {
+ return setConstraint(inputDefinition);
+ }
+
+ return Collections.emptyList();
+ }
+
+ private <T extends PropertyDataDefinition> List<PropertyConstraint> setConstraint(T inputDefinition) {
+ List<PropertyConstraint> constraints = new ArrayList<>();
+ String[] inputPathArr = inputDefinition.getSubPropertyInputPath().split("#");
+ if (inputPathArr.length > 1) {
+ inputPathArr = ArrayUtils.remove(inputPathArr, 0);
+ }
+
+ Map<String, DataTypeDefinition> 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<String, DataTypeDefinition> dataTypeDefinitionMap,
+ String propertyType,
+ String anInputPathArr,
+ List<PropertyConstraint> constraints) {
+ String type = null;
+ List<PropertyDefinition> 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<Boolean, ResponseFormat> 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<ComponentInstance, StorageOperationStatus> 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<String, List<ComponentInstanceInput>> ciInputs = Optional.ofNullable(component.getComponentInstancesInputs()).orElse(Collections.emptyMap());
+ Map<String, List<ComponentInstanceInput>> 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<List<ComponentInstanceProperty>, 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<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponent = validateComponentExists(componentId, componentType, componentParametersView);
@@ -269,6 +285,14 @@ public class InputsBusinessLogic extends BaseBusinessLogic {
return result;
}
+ //Validate value and Constraint of input
+ Either<Boolean, ResponseFormat> 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<Map<String, DataTypeDefinition>, ResponseFormat> allDataTypes = getAllDataTypes(applicationDataTypeCache);
if (allDataTypes.isRight()) {
result = Either.right(allDataTypes.right().value());
@@ -321,6 +345,29 @@ public class InputsBusinessLogic extends BaseBusinessLogic {
}
}
+ private Either<Boolean, ResponseFormat> validateInputValueConstraint(
+ org.openecomp.sdc.be.model.Component component, List<InputDefinition> inputs) {
+ PropertyValueConstraintValidationUtil propertyValueConstraintValidationUtil =
+ PropertyValueConstraintValidationUtil.getInstance();
+ List<InputDefinition> 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<List<ComponentInstanceInput>, 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<List<InputDefinition>, StorageOperationStatus> prepareInputsForCreation(String userId, String cmptId, List<InputDefinition> inputsToCreate) {
Map<String, InputDefinition> 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<String, List<String>> 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<UiComponentDataTransfer, ResponseFormat> getUiComponentDataTransferByComponentId(String resourceId, List<String> dataParamsToReturn) {
-
- ComponentParametersView paramsToRetuen = new ComponentParametersView(dataParamsToReturn);
- Either<Resource, StorageOperationStatus> 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<UiComponentDataTransfer, ResponseFormat> getUiComponentDataTransferByComponentId(String resourceId,
+ List<String> dataParamsToReturn) {
+
+ ComponentParametersView paramsToRetuen = new ComponentParametersView(dataParamsToReturn);
+ Either<Resource, StorageOperationStatus> 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<Component, ActionStatus> 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<Boolean, ResponseFormat> 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<Boolean, ResponseFormat> 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<Boolean, ResponseFormat> 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<PROPERTYOWNER extends Properties
input.setInputPath(propertiesName);
input.setInstanceUniqueId(propertiesOwner.getUniqueId());
input.setPropertyId(propInput.getUniqueId());
+ if (Objects.isNull(input.getSubPropertyInputPath())
+ || (Objects.nonNull(propertiesName)
+ && input.getSubPropertyInputPath().substring(input.getSubPropertyInputPath().lastIndexOf('#'))
+ .equals(propertiesName.substring(propertiesName.lastIndexOf('#'))))) {
+ input.setParentPropertyType(propInput.getType());
+ input.setSubPropertyInputPath(propertiesName);
+ }
+
changePropertyValueToGetInputValue(inputName, parsedPropNames, input, prop, complexProperty);
if(prop instanceof IComponentInstanceConnectedElement) {
@@ -169,7 +177,7 @@ public abstract class DefaultPropertyDeclarator<PROPERTYOWNER extends Properties
private void changePropertyValueToGetInputValue(String inputName, String[] parsedPropNames, InputDefinition input, PropertyDataDefinition prop, boolean complexProperty) {
JSONObject jobject = new JSONObject();
- String value = (String) prop.getValue();
+ String value = prop.getValue();
if(value == null || value.isEmpty()){
if(complexProperty){
@@ -185,7 +193,6 @@ public abstract class DefaultPropertyDeclarator<PROPERTYOWNER extends Properties
}else{
- //String value = value;
Object objValue = new Yaml().load(value);
if( objValue instanceof Map || objValue instanceof List){
if(!complexProperty){
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtil.java b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtil.java
new file mode 100644
index 0000000000..f2cdcc3a6d
--- /dev/null
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtil.java
@@ -0,0 +1,374 @@
+/*
+ * Copyright © 2016-2018 European Support Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openecomp.sdc.be.datamodel.utils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import fj.data.Either;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.ListUtils;
+import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.type.TypeReference;
+import org.openecomp.sdc.be.components.impl.ResponseFormatManager;
+import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.model.DataTypeDefinition;
+import org.openecomp.sdc.be.model.InputDefinition;
+import org.openecomp.sdc.be.model.PropertyConstraint;
+import org.openecomp.sdc.be.model.PropertyDefinition;
+import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache;
+import org.openecomp.sdc.be.model.tosca.ToscaType;
+import org.openecomp.sdc.be.model.tosca.constraints.ConstraintUtil;
+import org.openecomp.sdc.be.model.tosca.constraints.ValidValuesConstraint;
+import org.openecomp.sdc.be.model.tosca.constraints.exception.ConstraintValueDoNotMatchPropertyTypeException;
+import org.openecomp.sdc.be.model.tosca.constraints.exception.ConstraintViolationException;
+import org.openecomp.sdc.exception.ResponseFormat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PropertyValueConstraintValidationUtil {
+
+ private static final String UNDERSCORE = "_";
+ private static final String VALUE_PROVIDED_IN_INVALID_FORMAT_FOR_PROPERTY =
+ "%nValue provided in invalid format for %s property";
+ private Map<String, DataTypeDefinition> dataTypeDefinitionCache;
+ private static final Logger logger = LoggerFactory.getLogger(PropertyValueConstraintValidationUtil.class);
+ private ObjectMapper objectMapper = new ObjectMapper();
+ private List<String> 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<Boolean, ResponseFormat> validatePropertyConstraints(
+ Collection<? extends PropertyDefinition> 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<PropertyDefinition> propertyDefinitions =
+ dataTypeDefinitionCache.get(propertyDefinition.getType()).getProperties();
+ try {
+ Map<String, Object> valueMap =
+ MapUtils.emptyIfNull(ConstraintUtil.parseToCollection(propertyDefinition.getValue(),
+ new TypeReference<Map<String, Object>>() {}));
+
+ 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<String, Object> 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<List<Object>>() {});
+ 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<Map<String, Object>>() {
+ });
+ 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<PropertyConstraint> 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<String, Object> inputMap = new HashMap<>();
+ PropertyDefinition propertyDefinition = new PropertyDefinition();
+ String[] inputPathArr = inputDefinition.getInputPath().split("#");
+ if (inputPathArr.length > 1) {
+ inputPathArr = ArrayUtils.remove(inputPathArr, 0);
+ }
+
+ try {
+ Map<String, Object> 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<String, Object>());
+ presentMap = (Map<String, Object>) 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<Boolean, ResponseFormat> 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<OperationInputDefinition> 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<OperationInputDefinition> 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<String, Object> valueAsMap = (new Gson()).fromJson(value, Map.class);
- String toscaFunction = valueAsMap.keySet().iterator().next();
- Object consumptionValueName = valueAsMap.values().iterator().next();
- if(consumptionValueName instanceof List) {
- List<Object> toscaFunctionList = (List<Object>) 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<OperationInput> updateOperationInputListForUi(List<OperationInputDefinition> inputsList,
+ InterfaceOperationBusinessLogic interfaceOperationBL) {
+ List<OperationInput> 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<String, Object> valueAsMap = (new Gson()).fromJson(value, Map.class);
+ String toscaFunction = valueAsMap.keySet().iterator().next();
+ Object consumptionValueName = valueAsMap.values().iterator().next();
+ if(consumptionValueName instanceof List) {
+ List<Object> toscaFunctionList = (List<Object>) 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<Map<String, List<ServiceConsumptionData>>, ResponseFormat> getServiceConsumptionData(String data,
User user) {
diff --git a/catalog-be/src/main/resources/config/error-configuration.yaml b/catalog-be/src/main/resources/config/error-configuration.yaml
index d9f8ffc7e4..312d90c307 100644
--- a/catalog-be/src/main/resources/config/error-configuration.yaml
+++ b/catalog-be/src/main/resources/config/error-configuration.yaml
@@ -2262,4 +2262,10 @@ errors:
code: 400,
message: "Error: Given value is different than input type. Needs to be %1",
messageId: "SVC4725"
+ }
+#---------SVC4726-----------------------------
+ INVALID_PROPERTY_VALUES: {
+ code: 400,
+ message: "Error: Invalid property values provided:\n %1",
+ messageId: "SVC4735"
} \ No newline at end of file
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtilTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtilTest.java
new file mode 100644
index 0000000000..95020b6112
--- /dev/null
+++ b/catalog-be/src/test/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtilTest.java
@@ -0,0 +1,317 @@
+package org.openecomp.sdc.be.datamodel.utils;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.reflect.TypeToken;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.lang.reflect.Type;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import fj.data.Either;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.openecomp.sdc.be.components.impl.ResponseFormatManager;
+import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
+import org.openecomp.sdc.be.model.ComponentInstanceProperty;
+import org.openecomp.sdc.be.model.DataTypeDefinition;
+import org.openecomp.sdc.be.model.InputDefinition;
+import org.openecomp.sdc.be.model.PropertyConstraint;
+import org.openecomp.sdc.be.model.PropertyDefinition;
+import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache;
+import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade;
+import org.openecomp.sdc.be.model.operations.impl.PropertyOperation;
+import org.openecomp.sdc.exception.ResponseFormat;
+
+public class PropertyValueConstraintValidationUtilTest {
+
+ @Mock
+ ApplicationDataTypeCache applicationDataTypeCache;
+
+ @Mock
+ ToscaOperationFacade toscaOperationFacade;
+
+ @Spy
+ @InjectMocks
+ PropertyValueConstraintValidationUtil propertyValueConstraintValidationUtil;
+
+ private Map<String, DataTypeDefinition> dataTypeDefinitionMap;
+
+ @Before
+ public void init() {
+ MockitoAnnotations.initMocks(this);
+ ResponseFormatManager responseFormatManagerMock = Mockito.mock(ResponseFormatManager.class);
+ when(responseFormatManagerMock.getResponseFormat(any())).thenReturn(new ResponseFormat());
+ when(responseFormatManagerMock.getResponseFormat(any(), any())).thenReturn(new ResponseFormat());
+ when(responseFormatManagerMock.getResponseFormat(any(), any(), any())).thenReturn(new ResponseFormat());
+ when(propertyValueConstraintValidationUtil.getResponseFormatManager()).thenReturn(responseFormatManagerMock);
+
+ createDataTypeMap();
+ }
+
+ @Test
+ public void primitiveValueSuccessTest() {
+ Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap);
+ Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either);
+
+ PropertyDefinition propertyDefinition = new PropertyDefinition();
+ propertyDefinition.setType("integer");
+ propertyDefinition.setValue("10");
+
+ Either<Boolean, ResponseFormat> responseEither =
+ propertyValueConstraintValidationUtil.validatePropertyConstraints(
+ Collections.singletonList(propertyDefinition), applicationDataTypeCache);
+
+ Assert.assertTrue(responseEither.isLeft());
+ }
+
+ @Test
+ public void primitiveValueFailTest() {
+ Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap);
+ Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either);
+
+ PropertyDefinition propertyDefinition = new PropertyDefinition();
+ propertyDefinition.setType("integer");
+ propertyDefinition.setValue("abcd");
+
+ Either<Boolean, ResponseFormat> responseEither =
+ propertyValueConstraintValidationUtil.validatePropertyConstraints(
+ Collections.singletonList(propertyDefinition), applicationDataTypeCache);
+
+ Assert.assertTrue(responseEither.isRight());
+ }
+
+ @Test
+ public void complexWithValidValueSuccessTest() {
+ Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap);
+ Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either);
+
+ PropertyDefinition propertyDefinition = new PropertyDefinition();
+ propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet");
+ propertyDefinition.setValue("{\"prefixlen\":\"4\"}");
+
+ Either<Boolean, ResponseFormat> responseEither =
+ propertyValueConstraintValidationUtil.validatePropertyConstraints(
+ Collections.singletonList(propertyDefinition), applicationDataTypeCache);
+
+ Assert.assertTrue(responseEither.isLeft());
+ }
+
+ @Test
+ public void complexWithValidValueFailTest() {
+ Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap);
+ Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either);
+
+ PropertyDefinition propertyDefinition = new PropertyDefinition();
+ propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet");
+ propertyDefinition.setValue("{\"prefixlen\":\"5\"}");
+
+ Either<Boolean, ResponseFormat> responseEither =
+ propertyValueConstraintValidationUtil.validatePropertyConstraints(
+ Collections.singletonList(propertyDefinition), applicationDataTypeCache);
+
+ Assert.assertTrue(responseEither.isRight());
+ }
+
+ @Test
+ public void complexWithListWithPrimitiveValueSuccessTest() {
+ Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap);
+ Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either);
+
+ PropertyDefinition propertyDefinition = new PropertyDefinition();
+ propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet");
+ propertyDefinition.setValue("{\"allocation_pools\":[\"slaac\"]}");
+
+ Either<Boolean, ResponseFormat> responseEither =
+ propertyValueConstraintValidationUtil.validatePropertyConstraints(
+ Collections.singletonList(propertyDefinition), applicationDataTypeCache);
+
+ Assert.assertTrue(responseEither.isLeft());
+ }
+
+ @Test
+ public void complexWithListWithPrimitiveValueFailTest() {
+ Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap);
+ Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either);
+
+ PropertyDefinition propertyDefinition = new PropertyDefinition();
+ propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet");
+ propertyDefinition.setValue("{\"allocation_pools\":[\"value\"]}");
+
+ Either<Boolean, ResponseFormat> responseEither =
+ propertyValueConstraintValidationUtil.validatePropertyConstraints(
+ Collections.singletonList(propertyDefinition), applicationDataTypeCache);
+
+ Assert.assertTrue(responseEither.isRight());
+ }
+
+ @Test
+ public void complexWithMapWithPrimitiveValueSuccessTest() {
+ Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap);
+ Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either);
+
+ PropertyDefinition propertyDefinition = new PropertyDefinition();
+ propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet");
+ propertyDefinition.setValue("{\"value_specs\":{\"key\":\"slaac\"}}");
+
+ Either<Boolean, ResponseFormat> responseEither =
+ propertyValueConstraintValidationUtil.validatePropertyConstraints(
+ Collections.singletonList(propertyDefinition), applicationDataTypeCache);
+
+ Assert.assertTrue(responseEither.isLeft());
+ }
+
+ @Test
+ public void complexWithMapWithPrimitiveValueFailTest() {
+ Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap);
+ Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either);
+
+ PropertyDefinition propertyDefinition = new PropertyDefinition();
+ propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet");
+ propertyDefinition.setValue("{\"value_specs\":{\"key\":\"value\"}}");
+
+ Either<Boolean, ResponseFormat> responseEither =
+ propertyValueConstraintValidationUtil.validatePropertyConstraints(
+ Collections.singletonList(propertyDefinition), applicationDataTypeCache);
+
+ Assert.assertTrue(responseEither.isRight());
+ }
+
+ @Test
+ public void inputValidValueSuccessTest() {
+ Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap);
+ Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either);
+
+ InputDefinition inputDefinition = new InputDefinition();
+ inputDefinition.setInputPath("propetyName#ipv6_ra_mode");
+ inputDefinition.setDefaultValue("slaac");
+ inputDefinition.setType("string");
+ ComponentInstanceProperty propertyDefinition = new ComponentInstanceProperty();
+ propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet");
+ inputDefinition.setProperties(Collections.singletonList(propertyDefinition));
+
+ Either<Boolean, ResponseFormat> responseEither =
+ propertyValueConstraintValidationUtil.validatePropertyConstraints(
+ Collections.singletonList(inputDefinition), applicationDataTypeCache);
+
+ Assert.assertTrue(responseEither.isLeft());
+ }
+
+ @Test
+ public void inputValidValueFailTest() {
+ Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap);
+ Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either);
+
+ InputDefinition inputDefinition = new InputDefinition();
+ inputDefinition.setInputPath("propetyName#ipv6_ra_mode");
+ inputDefinition.setDefaultValue("incorrectValue");
+ ComponentInstanceProperty propertyDefinition = new ComponentInstanceProperty();
+ propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet");
+ inputDefinition.setProperties(Collections.singletonList(propertyDefinition));
+
+ Either<Boolean, ResponseFormat> responseEither =
+ propertyValueConstraintValidationUtil.validatePropertyConstraints(
+ Collections.singletonList(inputDefinition), applicationDataTypeCache);
+
+ Assert.assertTrue(responseEither.isRight());
+ }
+
+ @Test
+ public void serviceConsumptionValidValueSuccessTest() {
+ Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap);
+ Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either);
+
+ PropertyDefinition propertyDefinition = new PropertyDefinition();
+ propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet");
+ propertyDefinition.setValue("{\"ipv6_ra_mode\":\"slaac\"}");
+ propertyDefinition.setName("ipv6_ra_mode");
+
+ Either<Boolean, ResponseFormat> responseEither =
+ propertyValueConstraintValidationUtil.validatePropertyConstraints(
+ Collections.singletonList(propertyDefinition), applicationDataTypeCache);
+
+ Assert.assertTrue(responseEither.isLeft());
+ }
+ @Test
+ public void serviceConsumptionValidValueFailTest() {
+ Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap);
+ Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either);
+
+ PropertyDefinition propertyDefinition = new PropertyDefinition();
+ propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet");
+ propertyDefinition.setValue("{\"ipv6_ra_mode\":\"incorrectValue\"}");
+ propertyDefinition.setName("ipv6_ra_mode");
+
+ Either<Boolean, ResponseFormat> responseEither =
+ propertyValueConstraintValidationUtil.validatePropertyConstraints(
+ Collections.singletonList(propertyDefinition), applicationDataTypeCache);
+
+ Assert.assertTrue(responseEither.isRight());
+ }
+
+ private void createDataTypeMap() {
+ Type constraintType = new TypeToken<PropertyConstraint>() {}.getType();
+ Type typeOfHashMap = new TypeToken<Map<String, DataTypeDefinition>>() { }.getType();
+ Gson gson = new GsonBuilder().registerTypeAdapter(constraintType,
+ new PropertyOperation.PropertyConstraintDeserialiser()).create();
+
+ dataTypeDefinitionMap = gson.fromJson(readFile(), typeOfHashMap);
+
+ DataTypeDefinition dataTypeDefinition = dataTypeDefinitionMap.get("org.openecomp.datatypes.heat.network"
+ + ".neutron.Subnet");
+
+ PropertyDefinition mapProperty = null;
+ PropertyDefinition listProperty = null;
+ List<PropertyConstraint> constraints = null;
+ for (PropertyDefinition propertyDefinition : dataTypeDefinition.getProperties()) {
+ if ("value_specs".equals(propertyDefinition.getName())) {
+ mapProperty = propertyDefinition;
+ } else if ("allocation_pools".equals(propertyDefinition.getName())) {
+ listProperty = propertyDefinition;
+ } else if ("ipv6_ra_mode".equals(propertyDefinition.getName())) {
+ constraints = propertyDefinition.getConstraints();
+ }
+ }
+
+ PropertyDefinition definition = new PropertyDefinition(mapProperty.getSchema().getProperty());
+ definition.setConstraints(constraints);
+ mapProperty.getSchema().setProperty(definition);
+
+ definition = new PropertyDefinition(listProperty.getSchema().getProperty());
+ definition.setConstraints(constraints);
+ listProperty.getSchema().setProperty(definition);
+ }
+
+ private static String readFile() {
+ StringBuilder stringBuilder = new StringBuilder();
+ File file = new File(Objects.requireNonNull(
+ PropertyValueConstraintValidationUtilTest.class.getClassLoader().getResource("types/datatypes"
+ + "/constraintTest.json")).getFile());
+ Path logFile = Paths.get(file.getAbsolutePath());
+ try (BufferedReader reader = Files.newBufferedReader(logFile, StandardCharsets.UTF_8)) {
+ reader.lines().forEach(stringBuilder::append);
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+ e.printStackTrace();
+ }
+ return stringBuilder.toString();
+ }
+
+}
diff --git a/catalog-be/src/test/resources/csars/with_groups.csar b/catalog-be/src/test/resources/csars/with_groups.csar
index 3859114aa5..3a9e9ab8e0 100644
--- a/catalog-be/src/test/resources/csars/with_groups.csar
+++ b/catalog-be/src/test/resources/csars/with_groups.csar
Binary files differ
diff --git a/catalog-be/src/test/resources/types/datatypes/constraintTest.json b/catalog-be/src/test/resources/types/datatypes/constraintTest.json
new file mode 100644
index 0000000000..9596e92436
--- /dev/null
+++ b/catalog-be/src/test/resources/types/datatypes/constraintTest.json
@@ -0,0 +1,405 @@
+{
+ "string": {
+ "derivedFrom": {
+ "name": "tosca.datatypes.Root",
+ "uniqueId": "tosca.datatypes.Root.datatype",
+ "description": "The TOSCA root Data Type all other TOSCA base Data Types derive from",
+ "creationTime": 1550136563278,
+ "modificationTime": 1550136563278,
+ "toscaPresentation": {}
+ },
+ "name": "string",
+ "uniqueId": "string.datatype",
+ "derivedFromName": "tosca.datatypes.Root",
+ "creationTime": 1550136564103,
+ "modificationTime": 1550136564103,
+ "toscaPresentation": {}
+ },
+ "org.openecomp.datatypes.heat.network.neutron.Subnet": {
+ "derivedFrom": {
+ "name": "tosca.datatypes.Root",
+ "uniqueId": "tosca.datatypes.Root.datatype",
+ "description": "The TOSCA root Data Type all other TOSCA base Data Types derive from",
+ "creationTime": 1550136563278,
+ "modificationTime": 1550136563278,
+ "toscaPresentation": {}
+ },
+ "properties": [
+ {
+ "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.tenant_id",
+ "type": "string",
+ "required": false,
+ "definition": false,
+ "description": "The ID of the tenant who owns the network",
+ "password": false,
+ "name": "tenant_id",
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ {
+ "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.enable_dhcp",
+ "type": "boolean",
+ "required": false,
+ "definition": false,
+ "defaultValue": "true",
+ "description": "Set to true if DHCP is enabled and false if DHCP is disabled",
+ "password": false,
+ "name": "enable_dhcp",
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ {
+ "constraints": [
+ {
+ "validValues": [
+ "dhcpv6-stateful",
+ "dhcpv6-stateless",
+ "slaac"
+ ]
+ }
+ ],
+ "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.ipv6_address_mode",
+ "type": "string",
+ "required": false,
+ "definition": false,
+ "description": "IPv6 address mode",
+ "password": false,
+ "name": "ipv6_address_mode",
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ {
+ "constraints": [
+ {
+ "validValues": [
+ "dhcpv6-stateful",
+ "dhcpv6-stateless",
+ "slaac"
+ ]
+ }
+ ],
+ "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.ipv6_ra_mode",
+ "type": "string",
+ "required": false,
+ "definition": false,
+ "description": "IPv6 RA (Router Advertisement) mode",
+ "password": false,
+ "name": "ipv6_ra_mode",
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ {
+ "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.value_specs",
+ "type": "map",
+ "required": false,
+ "definition": false,
+ "defaultValue": "{}",
+ "description": "Extra parameters to include in the request",
+ "schema": {
+ "property": {
+ "constraints": [
+ {
+ "validValues": [
+ "dhcpv6-stateful",
+ "dhcpv6-stateless",
+ "slaac"
+ ]
+ }
+ ],
+ "type": "string",
+ "required": true,
+ "definition": false,
+ "password": false,
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ "toscaPresentation": {}
+ },
+ "password": false,
+ "name": "value_specs",
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ {
+ "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.allocation_pools",
+ "type": "list",
+ "required": false,
+ "definition": false,
+ "description": "The start and end addresses for the allocation pools",
+ "schema": {
+ "property": {
+ "type": "string",
+ "required": true,
+ "definition": false,
+ "password": false,
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ "toscaPresentation": {}
+ },
+ "password": false,
+ "name": "allocation_pools",
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ {
+ "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.subnetpool",
+ "type": "string",
+ "required": false,
+ "definition": false,
+ "description": "The name or ID of the subnet pool",
+ "password": false,
+ "name": "subnetpool",
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ {
+ "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.dns_nameservers",
+ "type": "list",
+ "required": false,
+ "definition": false,
+ "defaultValue": "[]",
+ "description": "A specified set of DNS name servers to be used",
+ "schema": {
+ "property": {
+ "type": "string",
+ "required": true,
+ "definition": false,
+ "password": false,
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ "toscaPresentation": {}
+ },
+ "password": false,
+ "name": "dns_nameservers",
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ {
+ "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.host_routes",
+ "type": "list",
+ "required": false,
+ "definition": false,
+ "description": "The gateway IP address",
+ "schema": {
+ "property": {
+ "type": "org.openecomp.datatypes.heat.network.subnet.HostRoute",
+ "required": true,
+ "definition": false,
+ "password": false,
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ "toscaPresentation": {}
+ },
+ "password": false,
+ "name": "host_routes",
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ {
+ "constraints": [
+ {
+ "validValues": [
+ "4",
+ "6"
+ ]
+ }
+ ],
+ "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.ip_version",
+ "type": "integer",
+ "required": false,
+ "definition": false,
+ "defaultValue": "4",
+ "description": "The gateway IP address",
+ "password": false,
+ "name": "ip_version",
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ {
+ "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.name",
+ "type": "string",
+ "required": false,
+ "definition": false,
+ "description": "The name of the subnet",
+ "password": false,
+ "name": "name",
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ {
+ "constraints": [
+ {
+ "greaterOrEqual": "0"
+ },
+ {
+ "validValues": [
+ "4",
+ "6"
+ ]
+ }
+ ],
+ "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.prefixlen",
+ "type": "integer",
+ "required": false,
+ "definition": false,
+ "description": "Prefix length for subnet allocation from subnet pool",
+ "password": false,
+ "name": "prefixlen",
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ {
+ "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.cidr",
+ "type": "string",
+ "required": false,
+ "definition": false,
+ "description": "The CIDR",
+ "password": false,
+ "name": "cidr",
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ {
+ "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.gateway_ip",
+ "type": "string",
+ "required": false,
+ "definition": false,
+ "description": "The gateway IP address",
+ "password": false,
+ "name": "gateway_ip",
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ }
+ ],
+ "name": "org.openecomp.datatypes.heat.network.neutron.Subnet",
+ "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype",
+ "derivedFromName": "tosca.datatypes.Root",
+ "description": "A subnet represents an IP address block that can be used for assigning IP addresses to virtual instances",
+ "creationTime": 1550136564412,
+ "modificationTime": 1550136564464,
+ "toscaPresentation": {}
+ },
+ "org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.MacAddress": {
+ "derivedFrom": {
+ "name": "tosca.datatypes.Root",
+ "uniqueId": "tosca.datatypes.Root.datatype",
+ "description": "The TOSCA root Data Type all other TOSCA base Data Types derive from",
+ "creationTime": 1550136563278,
+ "modificationTime": 1550136563278,
+ "toscaPresentation": {}
+ },
+ "properties": [
+ {
+ "uniqueId": "org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.MacAddress.datatype.mac_address",
+ "type": "list",
+ "required": false,
+ "definition": false,
+ "description": "Mac Addresses List.",
+ "schema": {
+ "property": {
+ "type": "string",
+ "required": true,
+ "definition": false,
+ "password": false,
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ "toscaPresentation": {}
+ },
+ "password": false,
+ "name": "mac_address",
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ }
+ ],
+ "name": "org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.MacAddress",
+ "uniqueId": "org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.MacAddress.datatype",
+ "derivedFromName": "tosca.datatypes.Root",
+ "description": "Virtual Machine Sub Interface Mac Address.",
+ "creationTime": 1550136565026,
+ "modificationTime": 1550136565030,
+ "toscaPresentation": {}
+ },
+ "org.openecomp.datatypes.heat.contrailV2.network.rule.RuleList": {
+ "derivedFrom": {
+ "name": "tosca.datatypes.Root",
+ "uniqueId": "tosca.datatypes.Root.datatype",
+ "description": "The TOSCA root Data Type all other TOSCA base Data Types derive from",
+ "creationTime": 1550136563278,
+ "modificationTime": 1550136563278,
+ "toscaPresentation": {}
+ },
+ "properties": [
+ {
+ "uniqueId": "org.openecomp.datatypes.heat.contrailV2.network.rule.RuleList.datatype.network_policy_entries_policy_rule",
+ "type": "list",
+ "required": false,
+ "definition": false,
+ "description": "Contrail network rule",
+ "schema": {
+ "property": {
+ "type": "org.openecomp.datatypes.heat.contrailV2.network.rule.Rule",
+ "required": true,
+ "definition": false,
+ "password": false,
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ },
+ "toscaPresentation": {}
+ },
+ "password": false,
+ "name": "network_policy_entries_policy_rule",
+ "hidden": false,
+ "immutable": false,
+ "toscaPresentation": {}
+ }
+ ],
+ "name": "org.openecomp.datatypes.heat.contrailV2.network.rule.RuleList",
+ "uniqueId": "org.openecomp.datatypes.heat.contrailV2.network.rule.RuleList.datatype",
+ "derivedFromName": "tosca.datatypes.Root",
+ "description": "list of policy rules",
+ "creationTime": 1550136564716,
+ "modificationTime": 1550136564720,
+ "toscaPresentation": {}
+ },
+ "integer": {
+ "derivedFrom": {
+ "name": "tosca.datatypes.Root",
+ "uniqueId": "tosca.datatypes.Root.datatype",
+ "description": "The TOSCA root Data Type all other TOSCA base Data Types derive from",
+ "creationTime": 1550136563278,
+ "modificationTime": 1550136563278,
+ "toscaPresentation": {}
+ },
+ "name": "integer",
+ "uniqueId": "integer.datatype",
+ "derivedFromName": "tosca.datatypes.Root",
+ "creationTime": 1550136564094,
+ "modificationTime": 1550136564094,
+ "toscaPresentation": {}
+ }
+} \ No newline at end of file