Fix 'Order of TOSCA.meta field is hardcoded'-bug
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / ComponentInstanceBusinessLogic.java
index f4daea7..ff98163 100644 (file)
@@ -17,6 +17,7 @@
  * limitations under the License.
  * ============LICENSE_END=========================================================
  */
+
 package org.openecomp.sdc.be.components.impl;
 
 import static org.openecomp.sdc.be.components.attribute.GetOutputUtils.isGetOutputValueForOutput;
@@ -43,10 +44,15 @@ import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.text.StringEscapeUtils;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.onap.sdc.tosca.datatypes.model.PropertyType;
 import org.openecomp.sdc.be.components.impl.exceptions.BusinessLogicException;
 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
+import org.openecomp.sdc.be.components.impl.exceptions.ToscaGetFunctionExceptionSupplier;
 import org.openecomp.sdc.be.components.impl.instance.ComponentInstanceChangeOperationOrchestrator;
 import org.openecomp.sdc.be.components.impl.utils.DirectivesUtil;
 import org.openecomp.sdc.be.components.merge.instance.ComponentInstanceMergeDataBusinessLogic;
@@ -60,6 +66,7 @@ import org.openecomp.sdc.be.dao.api.ActionStatus;
 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
 import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
+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;
@@ -69,9 +76,12 @@ import org.openecomp.sdc.be.datatypes.elements.GetPolicyValueDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
+import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionType;
+import org.openecomp.sdc.be.datatypes.elements.ToscaGetFunctionDataDefinition;
 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.datatypes.enums.PropertySource;
 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
 import org.openecomp.sdc.be.datatypes.tosca.ToscaGetFunctionType;
 import org.openecomp.sdc.be.exception.BusinessException;
@@ -97,12 +107,14 @@ import org.openecomp.sdc.be.model.InterfaceDefinition;
 import org.openecomp.sdc.be.model.LifecycleStateEnum;
 import org.openecomp.sdc.be.model.OutputDefinition;
 import org.openecomp.sdc.be.model.PolicyDefinition;
+import org.openecomp.sdc.be.model.PropertyConstraint;
 import org.openecomp.sdc.be.model.PropertyDefinition;
 import org.openecomp.sdc.be.model.RelationshipInfo;
 import org.openecomp.sdc.be.model.RequirementCapabilityRelDef;
 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.ToscaPropertyData;
 import org.openecomp.sdc.be.model.User;
 import org.openecomp.sdc.be.model.jsonjanusgraph.config.ContainerInstanceTypesData;
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
@@ -124,6 +136,7 @@ import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
+import org.openecomp.sdc.be.model.validation.ToscaFunctionValidator;
 import org.openecomp.sdc.be.resources.data.ComponentInstanceData;
 import org.openecomp.sdc.be.user.Role;
 import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum;
@@ -138,6 +151,7 @@ import org.openecomp.sdc.common.log.wrappers.Logger;
 import org.openecomp.sdc.common.util.ValidationUtils;
 import org.openecomp.sdc.exception.ResponseFormat;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.yaml.snakeyaml.Yaml;
 
 @org.springframework.stereotype.Component
 public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
@@ -156,7 +170,8 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
     private static final String CREATE_OR_UPDATE_PROPERTY_VALUE = "CreateOrUpdatePropertyValue";
     private static final String FAILED_TO_COPY_COMP_INSTANCE_TO_CANVAS = "Failed to copy the component instance to the canvas";
     private static final String COPY_COMPONENT_INSTANCE_OK = "Copy component instance OK";
-    private static final String CANNOT_ATTACH_RESOURCE_INSTANCES_TO_CONTAINER_RESOURCE_OF_TYPE = "Cannot attach resource instances to container resource of type {}";
+    private static final String CANNOT_ATTACH_RESOURCE_INSTANCES_TO_CONTAINER_RESOURCE_OF_TYPE =
+        "Cannot attach resource instances to container resource of type {}";
     private static final String FAILED_TO_UPDATE_COMPONENT_INSTANCE_CAPABILITY = "Failed to update component instance capability on instance {} in "
         + "container {}";
     private static final String SERVICE_PROXY = "serviceProxy";
@@ -167,14 +182,15 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
     private static final String RESTRICTED_OPERATION_ON_COMPONENT = "Restricted operation for user: {} on component {}";
     private static final String RESOURCE_INSTANCE = "resource instance";
     private static final String SERVICE = "service";
-    private static final String UPDATE_PROPERTY_CONTEXT = "UpdatePropertyValueOnComponentInstance";
-
-    private ComponentInstanceOperation componentInstanceOperation;
-    private ArtifactsBusinessLogic artifactBusinessLogic;
-    private ComponentInstanceMergeDataBusinessLogic compInstMergeDataBL;
-    private ComponentInstanceChangeOperationOrchestrator onChangeInstanceOperationOrchestrator;
-    private ForwardingPathOperation forwardingPathOperation;
-    private NodeFilterOperation nodeFilterOperation;
+
+    private final ComponentInstanceOperation componentInstanceOperation;
+    private final ArtifactsBusinessLogic artifactBusinessLogic;
+    private final ComponentInstanceMergeDataBusinessLogic compInstMergeDataBL;
+    private final ComponentInstanceChangeOperationOrchestrator onChangeInstanceOperationOrchestrator;
+    private final ForwardingPathOperation forwardingPathOperation;
+    private final NodeFilterOperation nodeFilterOperation;
+    private final ToscaFunctionValidator toscaFunctionValidator;
+    private final PropertyBusinessLogic propertyBusinessLogic;
     @Autowired
     private CompositionBusinessLogic compositionBusinessLogic;
     @Autowired
@@ -188,7 +204,8 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                                           ComponentInstanceMergeDataBusinessLogic compInstMergeDataBL,
                                           ComponentInstanceChangeOperationOrchestrator onChangeInstanceOperationOrchestrator,
                                           ForwardingPathOperation forwardingPathOperation, NodeFilterOperation nodeFilterOperation,
-                                          ArtifactsOperations artifactToscaOperation) {
+                                          ArtifactsOperations artifactToscaOperation, final ToscaFunctionValidator toscaFunctionValidator,
+                                          PropertyBusinessLogic propertyBusinessLogic) {
         super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation,
             artifactToscaOperation);
         this.componentInstanceOperation = componentInstanceOperation;
@@ -197,6 +214,8 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         this.onChangeInstanceOperationOrchestrator = onChangeInstanceOperationOrchestrator;
         this.forwardingPathOperation = forwardingPathOperation;
         this.nodeFilterOperation = nodeFilterOperation;
+        this.toscaFunctionValidator = toscaFunctionValidator;
+        this.propertyBusinessLogic = propertyBusinessLogic;
     }
 
     public ComponentInstance createComponentInstance(String containerComponentParam, String containerComponentId, String userId,
@@ -637,7 +656,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
     private void validateOriginComponentIsValidForContainer(Component containerComponent, ResourceTypeEnum resourceType) {
         switch (containerComponent.getComponentType()) {
             case SERVICE:
-                if (!containerInstanceTypesData.isAllowedForServiceComponent(resourceType)) {
+                if (!containerInstanceTypesData.isAllowedForServiceComponent(resourceType, containerComponent.getModel())) {
                     throw new ByActionStatusComponentException(ActionStatus.CONTAINER_CANNOT_CONTAIN_INSTANCE,
                         containerComponent.getComponentType().toString(), resourceType.name());
                 }
@@ -915,7 +934,8 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                     }
                     if (CollectionUtils.isNotEmpty(filteredGroups)) {
                         filteredGroups.stream()
-                            .filter(g -> g.getArtifacts().stream().anyMatch(p -> p.equals(artifactDefinition.getGeneratedFromId()))).findFirst()
+                            .filter(g -> g.getArtifacts() != null &&
+                                g.getArtifacts().stream().anyMatch(p -> p.equals(artifactDefinition.getGeneratedFromId()))).findFirst()
                             .ifPresent(g -> fillInstanceArtifactMap(groupInstancesArtifacts, artifactDefinition, g));
                     }
                 }
@@ -1263,6 +1283,9 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         oldComponentInstance.setModificationTime(System.currentTimeMillis());
         oldComponentInstance.setCustomizationUUID(UUID.randomUUID().toString());
         oldComponentInstance.setDirectives(newComponentInstance.getDirectives());
+        oldComponentInstance.setMaxOccurrences(newComponentInstance.getMaxOccurrences());
+        oldComponentInstance.setMinOccurrences(newComponentInstance.getMinOccurrences());
+        oldComponentInstance.setInstanceCount(newComponentInstance.getInstanceCount());
         if (oldComponentInstance.getGroupInstances() != null) {
             oldComponentInstance.getGroupInstances().forEach(group -> group.setName(getNewGroupName(oldComponentInstance.getNormalizedName(),
                 ValidationUtils.normalizeComponentInstanceName(newComponentInstance.getName()), group.getName())));
@@ -1941,6 +1964,12 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         }
         ComponentInstance foundResourceInstance = resourceInstanceStatus.left().value();
 
+        // Validate instance property against it's constrains
+        Either<Boolean, ResponseFormat> constraintValidatorResponse = validatePropertyValueConstraint(properties, componentId);
+        if (constraintValidatorResponse.isRight()) {
+            log.error("Failed validation value and constraint of property: {}", constraintValidatorResponse.right().value());
+            return Either.right(constraintValidatorResponse.right().value());
+        }
         // lock resource
         StorageOperationStatus lockStatus = graphLockOperation.lockComponent(componentId, componentTypeEnum.getNodeType());
         if (lockStatus != StorageOperationStatus.OK) {
@@ -1951,10 +1980,33 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         try {
             for (ComponentInstanceProperty property : properties) {
                 validateMandatoryFields(property);
-                ComponentInstanceProperty componentInstanceProperty = validatePropertyExistsOnComponent(property, containerComponent,
-                    foundResourceInstance);
+                validatePropertyExistsOnComponent(property, containerComponent, foundResourceInstance);
+                validatePropertyConstraintsNotChanged(properties, foundResourceInstance);
                 String propertyParentUniqueId = property.getParentUniqueId();
-                Either<String, ResponseFormat> updatedPropertyValue = updatePropertyObjectValue(property, false);
+                if (property.isToscaFunction()) {
+                    toscaFunctionValidator.validate(property, containerComponent);
+                    property.setValue(StringEscapeUtils.unescapeJava(property.getToscaFunction().getValue()));
+                    if (ToscaFunctionType.GET_INPUT == property.getToscaFunction().getType()) {
+                        property.setGetInputValues(Collections.singletonList(buildGetInputValue(property)));
+                    }
+                }
+                if (CollectionUtils.isNotEmpty(property.getSubPropertyToscaFunctions())) {
+                    ToscaPropertyType type = ToscaPropertyType.isValidType(property.getType());
+                    if (ToscaPropertyType.LIST.equals(type)) {
+                        final JSONArray jsonArray = property.getValue() == null ? new JSONArray() : new JSONArray(property.getValue());
+                        property.getSubPropertyToscaFunctions().stream().forEach(subToscaFunction -> {
+                            addE(jsonArray, subToscaFunction.getSubPropertyPath(), subToscaFunction.getToscaFunction().getValue());
+                        });
+                        property.setValue(jsonArray.toString());
+                    } else {
+                        final JSONObject jObject = property.getValue() == null ? new JSONObject() : new JSONObject(property.getValue());
+                        property.getSubPropertyToscaFunctions().stream().forEach(subToscaFunction -> {
+                            addE(jObject, subToscaFunction.getSubPropertyPath(), subToscaFunction.getToscaFunction().getValue());
+                        });
+                        property.setValue(jObject.toString());
+                    }
+                }
+                Either<String, ResponseFormat> updatedPropertyValue = updatePropertyObjectValue(property, containerComponent.getModel());
                 if (updatedPropertyValue.isRight()) {
                     log.error("Failed to update property object value of property: {}",
                         property);
@@ -1969,12 +2021,10 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                             capPropDefinition.get().getName()), Either::right);
                 } else {
                     updatedPropertyValue.bimap(
-                        updatedValue -> {
-                            componentInstanceProperty.setValue(updatedValue);
-                            return updatePropertyOnContainerComponent(property, updatedValue,
-                                containerComponent, foundResourceInstance);
-                        }, Either::right);
-                    updatedProperties.add(componentInstanceProperty);
+                        updatedValue -> updatePropertyOnContainerComponent(property, updatedValue, containerComponent, foundResourceInstance),
+                        Either::right
+                    );
+                    updatedProperties.add(property);
                 }
             }
 
@@ -2001,6 +2051,78 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         }
     }
 
+    private GetInputValueDataDefinition buildGetInputValue(final ComponentInstanceProperty property) {
+        final GetInputValueDataDefinition getInputValueDataDefinition = new GetInputValueDataDefinition();
+        getInputValueDataDefinition.setPropName(property.getName());
+        getInputValueDataDefinition.setInputName(((ToscaGetFunctionDataDefinition) property.getToscaFunction()).getPropertyName());
+        getInputValueDataDefinition.setInputId(((ToscaGetFunctionDataDefinition) property.getToscaFunction()).getPropertyUniqueId());
+        return getInputValueDataDefinition;
+    }
+
+    private void addE(JSONArray jsonArray, List<String> path, String value) {
+        Object objectForPath = jsonArray.opt(Integer.parseInt(path.get(0)));
+        if (objectForPath == null) {
+            if (path.size() > 1) {
+                if (StringUtils.isNumeric(path.get(1))) {
+                    objectForPath = new JSONArray();
+                } else {
+                    objectForPath = new JSONObject();
+                }
+                jsonArray.put(Integer.parseInt(path.get(0)), objectForPath);
+            }
+        }
+
+        if (path.size() == 1) {
+            Object valueAsObject = new Yaml().loadAs(value, Object.class);
+            jsonArray.put(Integer.parseInt(path.get(0)), valueAsObject);
+        } else {
+            if (objectForPath instanceof JSONObject) {
+                addE((JSONObject) objectForPath, path.subList(1, path.size()), value);
+            } else {
+                addE((JSONArray) objectForPath, path.subList(1, path.size()), value);
+            }
+        }
+    }
+
+    private void addE(JSONObject jsonObject, List<String> path, String value) {
+
+        Object objectForPath = null;
+        if (jsonObject.has(path.get(0))) {
+            objectForPath = jsonObject.get(path.get(0));
+        } else {
+            if (path.size() > 1 && StringUtils.isNumeric(path.get(1))) {
+                objectForPath = new JSONArray();
+            } else {
+                objectForPath = new JSONObject();
+            }
+            jsonObject.put(path.get(0), objectForPath);
+        }
+
+        if (path.size() == 1) {
+            Object valueAsObject = new Yaml().loadAs(value, Object.class);
+            jsonObject.put(path.get(0), valueAsObject);
+        } else {
+            if (objectForPath instanceof JSONObject) {
+                addE((JSONObject) objectForPath, path.subList(1, path.size()), value);
+            } else {
+                addE((JSONArray) objectForPath, path.subList(1, path.size()), value);
+            }
+        }
+    }
+
+    private void setJsonObjectForSubProperty(final JSONObject jObject, final List<String> path, String value) {
+        if (path.size() == 1) {
+            Object valueAsObject = new Yaml().loadAs(value, Object.class);
+            jObject.put(path.get(0), valueAsObject);
+        } else {
+            if (!jObject.has(path.get(0))) {
+                jObject.put(path.get(0), new JSONObject());
+            }
+            final JSONObject jsonObject = jObject.getJSONObject(path.get(0));
+            setJsonObjectForSubProperty(jsonObject, path.subList(1, path.size()), value);
+        }
+    }
+
     public Either<List<ComponentInstanceAttribute>, ResponseFormat> createOrUpdateAttributeValues(final ComponentTypeEnum componentTypeEnum,
                                                                                                   final String componentId,
                                                                                                   final String resourceInstanceId,
@@ -2042,6 +2164,22 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         }
         final ComponentInstance foundResourceInstance = resourceInstanceStatus.left().value();
 
+        // Validate instance attributes against it's constraints
+        List<PropertyDefinition> attributesToValidate = new ArrayList<>();
+        attributes.forEach((componentInstanceAttribute) -> {
+            PropertyDefinition propertyDefinition = new PropertyDefinition();
+            propertyDefinition.setValue(componentInstanceAttribute.getValue());
+            propertyDefinition.setType(componentInstanceAttribute.getType());
+            propertyDefinition.setName(componentInstanceAttribute.getName());
+            propertyDefinition.setUniqueId(componentInstanceAttribute.getUniqueId());
+            attributesToValidate.add(propertyDefinition);
+        });
+        Either<Boolean, ResponseFormat> constraintValidatorResponse = validatePropertyValueConstraint(attributesToValidate, componentId);
+        if (constraintValidatorResponse.isRight()) {
+            log.error("Failed validation value and constraint of attribute: {}", constraintValidatorResponse.right().value());
+            return Either.right(constraintValidatorResponse.right().value());
+        }
+
         // lock resource
         final StorageOperationStatus lockStatus = graphLockOperation.lockComponent(componentId, componentTypeEnum.getNodeType());
         if (lockStatus != StorageOperationStatus.OK) {
@@ -2097,16 +2235,14 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         }
     }
 
-    private ComponentInstanceProperty validatePropertyExistsOnComponent(ComponentInstanceProperty property, Component containerComponent,
-                                                                        ComponentInstance foundResourceInstance) {
+    private void validatePropertyExistsOnComponent(ComponentInstanceProperty property, Component containerComponent,
+                                                   ComponentInstance foundResourceInstance) {
         List<ComponentInstanceProperty> instanceProperties = containerComponent.getComponentInstancesProperties()
             .get(foundResourceInstance.getUniqueId());
-        Optional<ComponentInstanceProperty> instanceProperty = instanceProperties.stream().filter(p -> p.getName().equals(property.getName()))
-            .findAny();
-        if (!instanceProperty.isPresent()) {
+        final boolean hasProperty = instanceProperties.stream().anyMatch(p -> p.getName().equals(property.getName()));
+        if (!hasProperty) {
             throw new ByActionStatusComponentException(ActionStatus.PROPERTY_NOT_FOUND, property.getName());
         }
-        return instanceProperty.get();
     }
 
     private ComponentInstanceAttribute validateAttributeExistsOnComponent(final ComponentInstanceAttribute attribute,
@@ -2265,21 +2401,21 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         return false;
     }
 
-    private <T extends PropertyDefinition> Either<String, ResponseFormat> updatePropertyObjectValue(T property, boolean isInput) {
-        final Map<String, DataTypeDefinition> allDataTypes = componentsUtils.getAllDataTypes(applicationDataTypeCache, property.getModel());
+    private <T extends PropertyDefinition> Either<String, ResponseFormat> updatePropertyObjectValue(T property, final String model) {
+        final Map<String, DataTypeDefinition> allDataTypes = componentsUtils.getAllDataTypes(applicationDataTypeCache, model);
         String innerType = null;
         String propertyType = property.getType();
         ToscaPropertyType type = ToscaPropertyType.isValidType(propertyType);
         log.debug("The type of the property {} is {}", property.getUniqueId(), propertyType);
 
         if (type == ToscaPropertyType.LIST || type == ToscaPropertyType.MAP) {
-            SchemaDefinition def = property.getSchema();
-            if (def == null) {
+            SchemaDefinition schema = property.getSchema();
+            if (schema == null) {
                 log.debug("Schema doesn't exists for property of type {}", type);
                 return Either
                     .right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(StorageOperationStatus.INVALID_VALUE)));
             }
-            PropertyDataDefinition propDef = def.getProperty();
+            PropertyDataDefinition propDef = schema.getProperty();
             if (propDef == null) {
                 log.debug("Property in Schema Definition inside property of type {} doesn't exist", type);
                 return Either
@@ -2291,8 +2427,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         // Specific Update Logic
         String newValue = property.getValue();
 
-        if (property.getToscaGetFunctionType() != null) {
-            validateToscaGetFunction(property);
+        if (property.hasToscaFunction() || CollectionUtils.isNotEmpty(property.getSubPropertyToscaFunctions())) {
             return Either.left(newValue);
         }
 
@@ -2310,14 +2445,12 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                 newValue = object.toString();
             }
         }
-        if (!isInput) {
-            ImmutablePair<String, Boolean> pair = propertyOperation
-                .validateAndUpdateRules(propertyType, ((ComponentInstanceProperty) property).getRules(), innerType, allDataTypes, true);
-            if (pair.getRight() != null && Boolean.FALSE.equals(pair.getRight())) {
-                BeEcompErrorManager.getInstance().logBeInvalidValueError("Add property value", pair.getLeft(), property.getName(), propertyType);
-                return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(
-                    DaoStatusConverter.convertJanusGraphStatusToStorageStatus(JanusGraphOperationStatus.ILLEGAL_ARGUMENT))));
-            }
+        ImmutablePair<String, Boolean> pair = propertyOperation
+            .validateAndUpdateRules(propertyType, ((ComponentInstanceProperty) property).getRules(), innerType, allDataTypes, true);
+        if (pair.getRight() != null && Boolean.FALSE.equals(pair.getRight())) {
+            BeEcompErrorManager.getInstance().logBeInvalidValueError("Add property value", pair.getLeft(), property.getName(), propertyType);
+            return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(
+                DaoStatusConverter.convertJanusGraphStatusToStorageStatus(JanusGraphOperationStatus.ILLEGAL_ARGUMENT))));
         }
         return Either.left(newValue);
     }
@@ -2365,29 +2498,148 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         return Either.left(newValue);
     }
 
-    private <T extends PropertyDefinition> void validateToscaGetFunction(T property) {
-        if (property.getToscaGetFunctionType() == ToscaGetFunctionType.GET_INPUT) {
-            final List<GetInputValueDataDefinition> getInputValues = property.getGetInputValues();
-            if (CollectionUtils.isEmpty(getInputValues)) {
-                log.debug("No input information provided. Cannot set get_input.");
-                throw new ByActionStatusComponentException(ActionStatus.INVALID_CONTENT);
-            }
-            if (getInputValues.size() > 1) {
-                log.debug("More than one input provided. Cannot set get_input.");
-                throw new ByActionStatusComponentException(ActionStatus.INVALID_CONTENT);
+    private <T extends PropertyDefinition> void validateToscaGetFunction(T property, Component parentComponent) {
+        final ToscaGetFunctionDataDefinition toscaGetFunction = (ToscaGetFunctionDataDefinition) property.getToscaFunction();
+        validateGetToscaFunctionAttributes(toscaGetFunction);
+        validateGetPropertySource(toscaGetFunction.getFunctionType(), toscaGetFunction.getPropertySource());
+        if (toscaGetFunction.getFunctionType() == ToscaGetFunctionType.GET_INPUT) {
+            validateGetFunction(property, parentComponent.getInputs(), parentComponent.getModel());
+            return;
+        }
+        if (toscaGetFunction.getFunctionType() == ToscaGetFunctionType.GET_PROPERTY) {
+            if (toscaGetFunction.getPropertySource() == PropertySource.SELF) {
+                validateGetFunction(property, parentComponent.getProperties(), parentComponent.getModel());
+            } else if (toscaGetFunction.getPropertySource() == PropertySource.INSTANCE) {
+                final ComponentInstance componentInstance =
+                    parentComponent.getComponentInstanceById(toscaGetFunction.getSourceUniqueId())
+                        .orElseThrow(ToscaGetFunctionExceptionSupplier.instanceNotFound(toscaGetFunction.getSourceName()));
+                validateGetFunction(property, componentInstance.getProperties(), parentComponent.getModel());
             }
-            final GetInputValueDataDefinition getInputValueDataDefinition = getInputValues.get(0);
 
-            if (!property.getType().equals(getInputValueDataDefinition.getInputType())) {
-                log.debug("Input type '{}' diverges from the property type '{}'. Cannot set get_input.",
-                    getInputValueDataDefinition.getInputType(), property.getType());
-                throw new ByActionStatusComponentException(ActionStatus.INVALID_CONTENT);
+            return;
+        }
+        if (toscaGetFunction.getFunctionType() == ToscaGetFunctionType.GET_ATTRIBUTE) {
+            if (toscaGetFunction.getPropertySource() == PropertySource.SELF) {
+                validateGetFunction(property, parentComponent.getAttributes(), parentComponent.getModel());
+            } else if (toscaGetFunction.getPropertySource() == PropertySource.INSTANCE) {
+                final ComponentInstance componentInstance =
+                    parentComponent.getComponentInstanceById(toscaGetFunction.getSourceUniqueId())
+                        .orElseThrow(ToscaGetFunctionExceptionSupplier.instanceNotFound(toscaGetFunction.getSourceName()));
+                validateGetFunction(property, componentInstance.getAttributes(), parentComponent.getModel());
             }
+
             return;
         }
 
-        throw new ByActionStatusComponentException(ActionStatus.NOT_SUPPORTED,
-            "Tosca function " + property.getToscaGetFunctionType().getToscaGetFunctionName());
+        throw ToscaGetFunctionExceptionSupplier.functionNotSupported(toscaGetFunction.getFunctionType()).get();
+    }
+
+    private <T extends PropertyDefinition> void validateGetFunction(final T property,
+                                                                    final List<? extends ToscaPropertyData> parentProperties,
+                                                                    final String model) {
+        final ToscaGetFunctionDataDefinition toscaGetFunction = (ToscaGetFunctionDataDefinition) property.getToscaFunction();
+        if (CollectionUtils.isEmpty(parentProperties)) {
+            throw ToscaGetFunctionExceptionSupplier
+                .propertyNotFoundOnTarget(toscaGetFunction.getPropertyName(), toscaGetFunction.getPropertySource(),
+                    toscaGetFunction.getFunctionType()
+                ).get();
+        }
+        final String getFunctionPropertyUniqueId = toscaGetFunction.getPropertyUniqueId();
+        ToscaPropertyData referredProperty = parentProperties.stream()
+            .filter(property1 -> getFunctionPropertyUniqueId.equals(property1.getUniqueId()))
+            .findFirst()
+            .orElseThrow(ToscaGetFunctionExceptionSupplier
+                .propertyNotFoundOnTarget(toscaGetFunction.getPropertyName(), toscaGetFunction.getPropertySource()
+                    , toscaGetFunction.getFunctionType())
+            );
+        if (toscaGetFunction.isSubProperty()) {
+            referredProperty = findSubProperty(referredProperty, toscaGetFunction, model);
+        }
+
+        if (!property.getType().equals(referredProperty.getType()) && !"list".equalsIgnoreCase(referredProperty.getType())) {
+            throw ToscaGetFunctionExceptionSupplier
+                .propertyTypeDiverge(toscaGetFunction.getType(), referredProperty.getType(), property.getType()).get();
+        }
+        if (PropertyType.typeHasSchema(referredProperty.getType()) && !referredProperty.getSchemaType().equals(property.getType())
+            && !"list".equalsIgnoreCase(referredProperty.getType()) && !referredProperty.getSchemaType().equals(property.getSchemaType())) {
+            throw ToscaGetFunctionExceptionSupplier
+                .propertySchemaDiverge(toscaGetFunction.getType(), referredProperty.getSchemaType(), property.getSchemaType()).get();
+        }
+    }
+
+    private ToscaPropertyData findSubProperty(final ToscaPropertyData referredProperty,
+                                              final ToscaGetFunctionDataDefinition toscaGetFunction,
+                                              final String model) {
+        final Map<String, DataTypeDefinition> dataTypeMap = loadDataTypes(model);
+        final List<String> propertyPathFromSource = toscaGetFunction.getPropertyPathFromSource();
+        DataTypeDefinition dataType = dataTypeMap.get(referredProperty.getType());
+        if (dataType == null) {
+            throw ToscaGetFunctionExceptionSupplier
+                .propertyDataTypeNotFound(propertyPathFromSource.get(0), referredProperty.getType(), toscaGetFunction.getFunctionType()).get();
+        }
+        ToscaPropertyData foundProperty = referredProperty;
+        for (int i = 1; i < propertyPathFromSource.size(); i++) {
+            final String currentPropertyName = propertyPathFromSource.get(i);
+            foundProperty = dataType.getProperties().stream()
+                .filter(propertyDefinition -> currentPropertyName.equals(propertyDefinition.getName())).findFirst()
+                .orElseThrow(
+                    ToscaGetFunctionExceptionSupplier
+                        .propertyNotFoundOnTarget(propertyPathFromSource.subList(0, i), toscaGetFunction.getPropertySource(),
+                            toscaGetFunction.getFunctionType())
+                );
+            dataType = dataTypeMap.get(foundProperty.getType());
+            if (dataType == null) {
+                throw ToscaGetFunctionExceptionSupplier
+                    .propertyDataTypeNotFound(propertyPathFromSource.subList(0, i), foundProperty.getType(),
+                        toscaGetFunction.getFunctionType()).get();
+            }
+        }
+        return foundProperty;
+    }
+
+    private Map<String, DataTypeDefinition> loadDataTypes(String model) {
+        final Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> dataTypeEither =
+            applicationDataTypeCache.getAll(model);
+        if (dataTypeEither.isRight()) {
+            throw ToscaGetFunctionExceptionSupplier.couldNotLoadDataTypes(model).get();
+        }
+        return dataTypeEither.left().value();
+    }
+
+    private void validateGetPropertySource(final ToscaGetFunctionType functionType, final PropertySource propertySource) {
+        if (functionType == ToscaGetFunctionType.GET_INPUT && propertySource != PropertySource.SELF) {
+            throw ToscaGetFunctionExceptionSupplier
+                .targetSourceNotSupported(functionType, propertySource).get();
+        }
+        if (functionType == ToscaGetFunctionType.GET_PROPERTY && !List.of(PropertySource.SELF, PropertySource.INSTANCE).contains(propertySource)) {
+            throw ToscaGetFunctionExceptionSupplier
+                .targetSourceNotSupported(functionType, propertySource).get();
+        }
+    }
+
+    private void validateGetToscaFunctionAttributes(final ToscaGetFunctionDataDefinition toscaGetFunction) {
+        if (toscaGetFunction.getFunctionType() == null) {
+            throw ToscaGetFunctionExceptionSupplier.targetFunctionTypeNotFound().get();
+        }
+        if (toscaGetFunction.getPropertySource() == null) {
+            throw ToscaGetFunctionExceptionSupplier.targetPropertySourceNotFound(toscaGetFunction.getFunctionType()).get();
+        }
+        if (CollectionUtils.isEmpty(toscaGetFunction.getPropertyPathFromSource())) {
+            throw ToscaGetFunctionExceptionSupplier
+                .targetSourcePathNotFound(toscaGetFunction.getFunctionType()).get();
+        }
+        if (StringUtils.isEmpty(toscaGetFunction.getSourceName()) || StringUtils.isBlank(toscaGetFunction.getSourceName())) {
+            throw ToscaGetFunctionExceptionSupplier.sourceNameNotFound(toscaGetFunction.getPropertySource()).get();
+        }
+        if (StringUtils.isEmpty(toscaGetFunction.getSourceUniqueId()) || StringUtils.isBlank(toscaGetFunction.getSourceUniqueId())) {
+            throw ToscaGetFunctionExceptionSupplier.sourceIdNotFound(toscaGetFunction.getPropertySource()).get();
+        }
+        if (StringUtils.isEmpty(toscaGetFunction.getPropertyName()) || StringUtils.isBlank(toscaGetFunction.getPropertyName())) {
+            throw ToscaGetFunctionExceptionSupplier.propertyNameNotFound(toscaGetFunction.getPropertySource()).get();
+        }
+        if (StringUtils.isEmpty(toscaGetFunction.getPropertyUniqueId()) || StringUtils.isBlank(toscaGetFunction.getPropertyUniqueId())) {
+            throw ToscaGetFunctionExceptionSupplier.propertyIdNotFound(toscaGetFunction.getPropertySource()).get();
+        }
     }
 
     private ResponseFormat updateInputOnContainerComponent(ComponentInstanceInput input, String newValue, Component containerComponent,
@@ -2799,8 +3051,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
             }
 
             Component eitherOriginComponent = getInstanceOriginNode(currentResourceInstance);
-            DataForMergeHolder dataHolder = compInstMergeDataBL
-                .saveAllDataBeforeDeleting(containerComponent, currentResourceInstance, eitherOriginComponent);
+            DataForMergeHolder dataHolder = compInstMergeDataBL.saveAllDataBeforeDeleting(containerComponent, currentResourceInstance, eitherOriginComponent);
             ComponentInstance resResourceInfo = deleteComponentInstance(containerComponent, componentInstanceId,
                 containerComponentType);
 
@@ -2850,12 +3101,21 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                 } else {
                     origComponent = getOriginComponentFromComponentInstance(newComponentInstance);
                     newComponentInstance.setName(resResourceInfo.getName());
+                    final Map<String, InterfaceDefinition> componentInterfaces = origComponent.getInterfaces();
+                    if (MapUtils.isNotEmpty(componentInterfaces)) {
+                        componentInterfaces.forEach(newComponentInstance::addInterface);
+                    }
                 }
 
                 newComponentInstance.setInvariantName(resResourceInfo.getInvariantName());
                 newComponentInstance.setPosX(resResourceInfo.getPosX());
                 newComponentInstance.setPosY(resResourceInfo.getPosY());
                 newComponentInstance.setDescription(resResourceInfo.getDescription());
+                newComponentInstance.setInstanceCount(resResourceInfo.getInstanceCount());
+                newComponentInstance.setMaxOccurrences(resResourceInfo.getMaxOccurrences());
+                newComponentInstance.setMinOccurrences(resResourceInfo.getMinOccurrences());
+                newComponentInstance.setDirectives(resResourceInfo.getDirectives());
+                checkForExternalReqAndCapabilities(origComponent, resResourceInfo);
 
                 ComponentInstance updatedComponentInstance =
                     createComponentInstanceOnGraph(containerComponent, origComponent, newComponentInstance, user);
@@ -2879,8 +3139,10 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                     log.debug("Component with id {} was not found", containerComponentId);
                     throw new ByActionStatusComponentException(actionStatus, Constants.EMPTY_STRING);
                 }
-                resourceInstanceStatus = getResourceInstanceById(updatedComponentRes.left().value(),
-                    updatedComponentInstance.getUniqueId());
+
+                maintainNodeFilters(currentResourceInstance, newComponentInstance, containerComponentId);
+
+                resourceInstanceStatus = getResourceInstanceById(updatedComponentRes.left().value(), updatedComponentInstance.getUniqueId());
                 if (resourceInstanceStatus.isRight()) {
                     throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse
                         (resourceInstanceStatus.right().value()), updatedComponentInstance.getUniqueId());
@@ -2895,6 +3157,53 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         }
     }
 
+    private void maintainNodeFilters(
+        ComponentInstance currentResourceInstance,
+        ComponentInstance newComponentInstance,
+        String containerComponentId) {
+        CINodeFilterDataDefinition filterToMaintain = currentResourceInstance.getNodeFilter();
+        if (null != filterToMaintain) {
+            nodeFilterOperation.addNodeFilterData(
+                containerComponentId.toLowerCase(),
+                newComponentInstance.getUniqueId(),
+                filterToMaintain);
+        }
+    }
+
+    private void checkForExternalReqAndCapabilities(Component component, ComponentInstance resResourceInfo) {
+        if (MapUtils.isNotEmpty(component.getRequirements())) {
+            component.getRequirements().entrySet().forEach(requirementsMap -> {
+                if (MapUtils.isNotEmpty(resResourceInfo.getRequirements()) &&
+                    resResourceInfo.getRequirements().containsKey(requirementsMap.getKey())) {
+                    List<RequirementDefinition> resourceReqList = resResourceInfo.getRequirements().get(requirementsMap.getKey());
+                    for (RequirementDefinition requirements : requirementsMap.getValue()) {
+                        String requirementName = requirements.getName();
+                        resourceReqList.forEach(requirementDefinition -> {
+                            if (requirementName.equals(requirementDefinition.getName()) && requirementDefinition.isExternal()) {
+                                requirements.setExternal(requirementDefinition.isExternal());
+                            }
+                        });
+                    }
+                }
+            });
+        }
+        if (MapUtils.isNotEmpty(component.getCapabilities())) {
+            component.getCapabilities().entrySet().forEach(capabilityMap -> {
+                if (MapUtils.isNotEmpty(resResourceInfo.getCapabilities()) && resResourceInfo.getCapabilities().containsKey(capabilityMap.getKey())) {
+                    List<CapabilityDefinition> resourceCapList = resResourceInfo.getCapabilities().get(capabilityMap.getKey());
+                    capabilityMap.getValue().forEach(capabilities -> {
+                        String capabilityName = capabilities.getName();
+                        for (CapabilityDefinition capDef : resourceCapList) {
+                            if (capabilityName.equals(capDef.getName()) && capDef.isExternal()) {
+                                capabilities.setExternal(capDef.isExternal());
+                            }
+                        }
+                    });
+                }
+            });
+        }
+    }
+
     private boolean isFillProxyRes(StorageOperationStatus fillProxyRes) {
         if (fillProxyRes != StorageOperationStatus.OK) {
             log.debug("Failed to fill service proxy resource data with data from service, error {}", fillProxyRes);
@@ -2927,9 +3236,10 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                     containerComponentId);
             }
 
-            List<ComponentInstanceProperty> instanceProperties = containerComponent.getComponentInstancesProperties().get(componentInstanceUniqueId);
-            if (CollectionUtils.isEmpty(instanceProperties)) {
-                instanceProperties = new ArrayList<>();
+            List<ComponentInstanceProperty> instanceProperties = new ArrayList<>();
+            if (MapUtils.isNotEmpty(containerComponent.getComponentInstancesProperties())) {
+                instanceProperties = containerComponent.getComponentInstancesProperties()
+                    .get(componentInstanceUniqueId);
             }
             return instanceProperties;
         } catch (ComponentException e) {
@@ -3038,22 +3348,18 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         return ComponentValidations.validateNameIsUniqueInComponent(oldComponentInstance.getName(), newInstanceName, containerComponent);
     }
 
-    private Either<ComponentInstance, StorageOperationStatus> getResourceInstanceById(Component containerComponent, String instanceId) {
-        Either<ComponentInstance, StorageOperationStatus> result = Either.right(StorageOperationStatus.NOT_FOUND);
-        List<ComponentInstance> instances = containerComponent.getComponentInstances();
-        Optional<ComponentInstance> foundInstance = Optional.empty();
-        if (!CollectionUtils.isEmpty(instances)) {
-            if (result.isRight()) {
-                foundInstance = instances.stream().filter(i -> i.getUniqueId().equals(instanceId)).findFirst();
-                if (!foundInstance.isPresent()) {
-                    result = Either.right(StorageOperationStatus.NOT_FOUND);
-                }
-            }
-            if (result.isRight() && foundInstance.isPresent()) {
-                result = Either.left(foundInstance.get());
-            }
+    private Either<ComponentInstance, StorageOperationStatus> getResourceInstanceById(final Component containerComponent, final String instanceId) {
+        final List<ComponentInstance> instances = containerComponent.getComponentInstances();
+        if (CollectionUtils.isEmpty(instances)) {
+            return Either.right(StorageOperationStatus.NOT_FOUND);
         }
-        return result;
+
+        final Optional<ComponentInstance> foundInstance = instances.stream().filter(i -> i.getUniqueId().equals(instanceId)).findFirst();
+        if (foundInstance.isEmpty()) {
+            return Either.right(StorageOperationStatus.NOT_FOUND);
+        }
+
+        return Either.left(foundInstance.get());
     }
 
     private ComponentInstance buildComponentInstance(ComponentInstance resourceInstanceForUpdate, ComponentInstance origInstanceForUpdate) {
@@ -3522,7 +3828,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                     if (sourceAttributeName.equals(destAttribute.getName())) {
                         log.debug("Start to copy the attribute exists {}", sourceAttributeName);
                         sourceAttribute.setUniqueId(
-                            UniqueIdBuilder.buildResourceInstanceUniuqeId("attribute", destComponentInstanceId.split("\\.")[1], sourceAttributeName));
+                            UniqueIdBuilder.buildResourceInstanceUniqueId("attribute", destComponentInstanceId.split("\\.")[1], sourceAttributeName));
                         Either<ComponentInstanceAttribute, ResponseFormat> updateAttributeValueEither = createOrUpdateAttributeValueForCopyPaste(
                             ComponentTypeEnum.SERVICE, destComponent.getUniqueId(), destComponentInstanceId, sourceAttribute, userId);
                         if (updateAttributeValueEither.isRight()) {
@@ -3706,8 +4012,43 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         }
     }
 
+    private void validatePropertyConstraintsNotChanged(List<ComponentInstanceProperty> newProperties, ComponentInstance originalResourceInstance) {
+        for (ComponentInstanceProperty newProperty : newProperties) {
+            Optional<PropertyDefinition> originalProperty = originalResourceInstance.getProperties().stream()
+                .filter(prop -> prop.getUniqueId().equals(newProperty.getUniqueId())).findAny();
+            if (originalProperty.isPresent()) {
+                List<PropertyConstraint> originalConstraints = originalProperty.get().getConstraints();
+                List<PropertyConstraint> newConstraints = newProperty.getConstraints();
+                if (!Objects.equals(originalConstraints, newConstraints)) {
+                    throw new ByActionStatusComponentException(ActionStatus.CANNOT_CHANGE_CONSTRAINTS);
+                }
+            } else {
+                throw new ByActionStatusComponentException(ActionStatus.PROPERTY_NOT_FOUND, newProperty.getUniqueId());
+            }
+        }
+    }
+
+    private Either<Boolean, ResponseFormat> validatePropertyValueConstraint(List<? extends PropertyDefinition> properties, final String componentId) {
+        try {
+            String propertyModel = propertyBusinessLogic.getComponentModelByComponentId(componentId);
+            PropertyValueConstraintValidationUtil propertyValueConstraintValidationUtil = new PropertyValueConstraintValidationUtil();
+            return propertyValueConstraintValidationUtil.validatePropertyConstraints(properties, applicationDataTypeCache, propertyModel);
+        } catch (BusinessLogicException e) {
+            return Either.right(e.getResponseFormat());
+        }
+    }
+
     public void validateUser(final String userId) {
         final User user = userValidations.validateUserExists(userId);
         userValidations.validateUserRole(user, Arrays.asList(Role.DESIGNER, Role.ADMIN));
     }
+
+    public void setCompositionBusinessLogic(CompositionBusinessLogic compositionBusinessLogic) {
+        this.compositionBusinessLogic = compositionBusinessLogic;
+    }
+
+    public void setContainerInstanceTypesData(ContainerInstanceTypesData containerInstanceTypesData) {
+        this.containerInstanceTypesData = containerInstanceTypesData;
+    }
+
 }