Fix 'Changing VFC version on template wipes previously assigned property values based...
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / ComponentInstanceBusinessLogic.java
index e867d06..01e87a1 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,6 +44,8 @@ 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;
@@ -73,6 +76,7 @@ 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;
@@ -103,6 +107,7 @@ 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;
@@ -165,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";
@@ -183,12 +189,12 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
     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
     private ContainerInstanceTypesData containerInstanceTypesData;
-    private final ToscaFunctionValidator toscaFunctionValidator;
-    private final PropertyBusinessLogic propertyBusinessLogic;
 
     @Autowired
     public ComponentInstanceBusinessLogic(IElementOperation elementDao, IGroupOperation groupOperation,
@@ -928,7 +934,8 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                     }
                     if (CollectionUtils.isNotEmpty(filteredGroups)) {
                         filteredGroups.stream()
-                            .filter(g -> g.getArtifacts() != null && 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));
                     }
                 }
@@ -1958,7 +1965,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         ComponentInstance foundResourceInstance = resourceInstanceStatus.left().value();
 
         // Validate instance property against it's constrains
-        Either<Boolean, ResponseFormat> constraintValidatorResponse = validatePropertyValueConstraint(properties,componentId);
+        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());
@@ -1974,18 +1981,30 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
             for (ComponentInstanceProperty property : properties) {
                 validateMandatoryFields(property);
                 validatePropertyExistsOnComponent(property, containerComponent, foundResourceInstance);
+                validatePropertyConstraintsNotChanged(properties, foundResourceInstance);
                 String propertyParentUniqueId = property.getParentUniqueId();
                 if (property.isToscaFunction()) {
                     toscaFunctionValidator.validate(property, containerComponent);
-                    property.setValue(property.getToscaFunction().getValue());
+                    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())){
-                    final JSONObject jObject  = property.getValue() == null ? new JSONObject() : new JSONObject(property.getValue());
-                    property.getSubPropertyToscaFunctions().stream().forEach(subToscaFunction -> {
-                        setJsonObjectForSubProperty(jObject, subToscaFunction.getSubPropertyPath(), subToscaFunction.getToscaFunction().getValue());
-                    });
-                    property.setValue(jObject.toString());
+                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()) {
@@ -2031,7 +2050,66 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
             graphLockOperation.unlockComponent(componentId, componentTypeEnum.getNodeType());
         }
     }
-    
+
+    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);
@@ -2096,7 +2174,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
             propertyDefinition.setUniqueId(componentInstanceAttribute.getUniqueId());
             attributesToValidate.add(propertyDefinition);
         });
-        Either<Boolean, ResponseFormat> constraintValidatorResponse = validatePropertyValueConstraint(attributesToValidate,componentId);
+        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());
@@ -2158,7 +2236,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
     }
 
     private void validatePropertyExistsOnComponent(ComponentInstanceProperty property, Component containerComponent,
-                                                                        ComponentInstance foundResourceInstance) {
+                                                   ComponentInstance foundResourceInstance) {
         List<ComponentInstanceProperty> instanceProperties = containerComponent.getComponentInstancesProperties()
             .get(foundResourceInstance.getUniqueId());
         final boolean hasProperty = instanceProperties.stream().anyMatch(p -> p.getName().equals(property.getName()));
@@ -2478,11 +2556,12 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
             referredProperty = findSubProperty(referredProperty, toscaGetFunction, model);
         }
 
-        if (!property.getType().equals(referredProperty.getType())) {
+        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.getSchemaType())) {
+        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();
         }
@@ -3081,22 +3160,23 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
     }
 
     private void maintainNodeFilters(
-            ComponentInstance currentResourceInstance,
-            ComponentInstance newComponentInstance,
-            String containerComponentId) {
+        ComponentInstance currentResourceInstance,
+        ComponentInstance newComponentInstance,
+        String containerComponentId) {
         CINodeFilterDataDefinition filterToMaintain = currentResourceInstance.getNodeFilter();
         if (null != filterToMaintain) {
             nodeFilterOperation.addNodeFilterData(
-                    containerComponentId.toLowerCase(),
-                    newComponentInstance.getUniqueId(),
-                    filterToMaintain);
+                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())) {
+                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();
@@ -3934,6 +4014,22 @@ 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);