Fix 'Unable to save changed attributes default value' 06/120606/2
authorvasraz <vasyl.razinkov@est.tech>
Thu, 15 Apr 2021 09:03:58 +0000 (10:03 +0100)
committerChristophe Closset <christophe.closset@intl.att.com>
Mon, 19 Apr 2021 15:49:05 +0000 (15:49 +0000)
Implements missing functionality to save changed attribute

Change-Id: I1bc828ef133c8a2bf2fd6333a51fb46fc41b6547
Signed-off-by: Vasyl Razinkov <vasyl.razinkov@est.tech>
Issue-ID: SDC-3562

catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java
catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/AttributeOperation.java
catalog-ui/src/app/ng2/pages/attributes-outputs/attributes-outputs.page.component.ts

index d0c72e5..b602072 100644 (file)
@@ -79,6 +79,7 @@ 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.ArtifactDefinition;
+import org.openecomp.sdc.be.model.AttributeDefinition;
 import org.openecomp.sdc.be.model.CapabilityDefinition;
 import org.openecomp.sdc.be.model.Component;
 import org.openecomp.sdc.be.model.ComponentInstance;
@@ -997,7 +998,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
             throw new ByActionStatusComponentException(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND, componentInstance.getName(),
                 instanceType.getValue().toLowerCase());
         }
-        if (!validateParentStatus.left().value()) {
+        if (!Boolean.TRUE.equals(validateParentStatus.left().value())) {
             throw new ByActionStatusComponentException(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND_ON_CONTAINER, componentInstance.getName(),
                 instanceType.getValue().toLowerCase(), containerComponentType.getValue().toLowerCase(), containerComponentId);
         }
@@ -1062,7 +1063,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                         ComponentInstance updatedCi = op.get();
                         updatedCi = buildComponentInstance(updatedCi, origInst);
                         Boolean isUniqueName = validateInstanceNameUniquenessUponUpdate(containerComponent, origInst, updatedCi.getName());
-                        if (!isUniqueName) {
+                        if (!Boolean.TRUE.equals(isUniqueName)) {
                             CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG,
                                 "Failed to update the name of the component instance {} to {}. A component instance with the same name already exists. ",
                                 origInst.getName(), updatedCi.getName());
@@ -1137,7 +1138,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
             isNameChanged = true;
         }
         Boolean isUniqueName = validateInstanceNameUniquenessUponUpdate(containerComponent, oldComponentInstance, newInstanceName);
-        if (!isUniqueName) {
+        if (!Boolean.TRUE.equals(isUniqueName)) {
             CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG,
                 "Failed to update the name of the component instance {} to {}. A component instance with the same name already exists. ",
                 oldComponentInstance.getName(), newInstanceName);
@@ -1911,7 +1912,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         Component containerComponent = getResourceResult.left().value();
 
         if (!ComponentValidationUtils.canWorkOnComponent(containerComponent, userId)) {
-            if (containerComponent.isArchived()) {
+            if (Boolean.TRUE.equals(containerComponent.isArchived())) {
                 log.info("Component is archived. Component id: {}", componentId);
                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_IS_ARCHIVED, containerComponent.getName()));
             }
@@ -1986,6 +1987,96 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         }
     }
 
+    public Either<List<ComponentInstanceAttribute>, ResponseFormat> createOrUpdateAttributeValues(final ComponentTypeEnum componentTypeEnum,
+                                                                                                  final String componentId,
+                                                                                                  final String resourceInstanceId,
+                                                                                                  final List<ComponentInstanceAttribute> attributes,
+                                                                                                  final String userId) {
+        Either<List<ComponentInstanceAttribute>, ResponseFormat> resultOp = null;
+        /*-------------------------------Validations---------------------------------*/
+        validateUserExists(userId);
+
+        if (componentTypeEnum == null) {
+            BeEcompErrorManager.getInstance().logInvalidInputError("CreateOrUpdatePropertiesValues", INVALID_COMPONENT_TYPE, ErrorSeverity.INFO);
+            resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.NOT_ALLOWED));
+            return resultOp;
+        }
+        final Either<Component, StorageOperationStatus> getResourceResult = toscaOperationFacade
+            .getToscaElement(componentId, JsonParseFlagEnum.ParseAll);
+
+        if (getResourceResult.isRight()) {
+            log.debug(FAILED_TO_RETRIEVE_COMPONENT_COMPONENT_ID, componentId);
+            final ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getResourceResult.right().value(), componentTypeEnum);
+            return Either.right(componentsUtils.getResponseFormat(actionStatus, componentId));
+        }
+        final Component containerComponent = getResourceResult.left().value();
+
+        if (!ComponentValidationUtils.canWorkOnComponent(containerComponent, userId)) {
+            if (Boolean.TRUE.equals(containerComponent.isArchived())) {
+                log.info("Component is archived. Component id: {}", componentId);
+                return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_IS_ARCHIVED, containerComponent.getName()));
+            }
+            log.info("Restricted operation for user: {} on service {}", userId, componentId);
+            return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
+        }
+
+        final Either<ComponentInstance, StorageOperationStatus> resourceInstanceStatus = getResourceInstanceById(containerComponent,
+            resourceInstanceId);
+        if (resourceInstanceStatus.isRight()) {
+            return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND_ON_CONTAINER,
+                resourceInstanceId, "resource instance", "service", componentId));
+        }
+        final ComponentInstance foundResourceInstance = resourceInstanceStatus.left().value();
+
+        // lock resource
+        final StorageOperationStatus lockStatus = graphLockOperation.lockComponent(componentId, componentTypeEnum.getNodeType());
+        if (lockStatus != StorageOperationStatus.OK) {
+            log.debug(FAILED_TO_LOCK_SERVICE, componentId);
+            return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(lockStatus)));
+        }
+        final List<ComponentInstanceAttribute> updatedProperties = new ArrayList<>();
+        try {
+            for (final ComponentInstanceAttribute attribute : attributes) {
+                final ComponentInstanceAttribute componentInstanceProperty = validateAttributeExistsOnComponent(attribute, containerComponent,
+                    foundResourceInstance);
+                final Either<String, ResponseFormat> updatedPropertyValue = updateAttributeObjectValue(attribute);
+                if (updatedPropertyValue.isRight()) {
+                    log.error("Failed to update attribute object value of attribute: {}", attribute);
+                    throw new ByResponseFormatComponentException(updatedPropertyValue.right().value());
+                }
+                updatedPropertyValue.bimap(
+                    updatedValue -> {
+                        componentInstanceProperty.setValue(updatedValue);
+                        return updateAttributeOnContainerComponent(attribute, updatedValue,
+                            containerComponent, foundResourceInstance);
+                    }, Either::right);
+                updatedProperties.add(componentInstanceProperty);
+            }
+
+            final Either<Component, StorageOperationStatus> updateContainerRes = toscaOperationFacade
+                .updateComponentInstanceMetadataOfTopologyTemplate(containerComponent);
+            if (updateContainerRes.isRight()) {
+                final ActionStatus actionStatus = componentsUtils
+                    .convertFromStorageResponseForResourceInstanceProperty(updateContainerRes.right().value());
+                resultOp = Either.right(componentsUtils.getResponseFormatForResourceInstanceProperty(actionStatus, ""));
+                return resultOp;
+            }
+            resultOp = Either.left(updatedProperties);
+            return resultOp;
+
+        } catch (final ComponentException e) {
+            return Either.right(e.getResponseFormat());
+        } finally {
+            if (resultOp == null || resultOp.isRight()) {
+                janusGraphDao.rollback();
+            } else {
+                janusGraphDao.commit();
+            }
+            // unlock resource
+            graphLockOperation.unlockComponent(componentId, componentTypeEnum.getNodeType());
+        }
+    }
+
     private void validateMandatoryFields(PropertyDataDefinition property) {
         if (StringUtils.isEmpty(property.getName())) {
             throw new ByActionStatusComponentException(ActionStatus.MISSING_PROPERTY_NAME);
@@ -2004,6 +2095,19 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         return instanceProperty.get();
     }
 
+    private ComponentInstanceAttribute validateAttributeExistsOnComponent(final ComponentInstanceAttribute attribute,
+                                                                          final Component containerComponent,
+                                                                          final ComponentInstance foundResourceInstance) {
+        final List<ComponentInstanceAttribute> instanceProperties =
+            containerComponent.getComponentInstancesAttributes().get(foundResourceInstance.getUniqueId());
+        final Optional<ComponentInstanceAttribute> instanceAttribute =
+            instanceProperties.stream().filter(p -> p.getName().equals(attribute.getName())).findAny();
+        if (!instanceAttribute.isPresent()) {
+            throw new ByActionStatusComponentException(ActionStatus.PROPERTY_NOT_FOUND, attribute.getName());
+        }
+        return instanceAttribute.get();
+    }
+
     private ResponseFormat updateCapabilityPropertyOnContainerComponent(ComponentInstanceProperty property,
                                                                         String newValue, Component containerComponent,
                                                                         ComponentInstance foundResourceInstance,
@@ -2092,6 +2196,22 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         return componentsUtils.getResponseFormat(ActionStatus.OK);
     }
 
+    private ResponseFormat updateAttributeOnContainerComponent(final ComponentInstanceAttribute instanceAttribute,
+                                                               final String newValue,
+                                                               final Component containerComponent,
+                                                               final ComponentInstance foundResourceInstance) {
+
+        instanceAttribute.setValue(newValue);
+        final StorageOperationStatus status =
+            toscaOperationFacade.updateComponentInstanceAttribute(containerComponent, foundResourceInstance.getUniqueId(), instanceAttribute);
+        if (status != StorageOperationStatus.OK) {
+            final ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(status);
+            return componentsUtils.getResponseFormatForResourceInstanceProperty(actionStatus, "");
+        }
+        foundResourceInstance.setCustomizationUUID(UUID.randomUUID().toString());
+        return componentsUtils.getResponseFormat(ActionStatus.OK);
+    }
+
     private <T extends PropertyDefinition> Either<String, ResponseFormat> validatePropertyObjectValue(T property, String newValue, boolean isInput) {
         Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> allDataTypesEither = dataTypeCache.getAll();
         if (allDataTypesEither.isRight()) {
@@ -2110,8 +2230,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         Either<Object, Boolean> isValid = propertyOperation
             .validateAndUpdatePropertyValue(property.getType(), newValue, true, innerType, allDataTypes);
         if (isValid.isRight()) {
-            Boolean res = isValid.right().value();
-            if (!res) {
+            if (!Boolean.TRUE.equals(isValid.right().value())) {
                 log.error("Invalid value {} of property {} ", newValue, property.getName());
                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
             }
@@ -2184,8 +2303,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         Either<Object, Boolean> isValid = propertyOperation
             .validateAndUpdatePropertyValue(propertyType, property.getValue(), true, innerType, allDataTypes);
         if (isValid.isRight()) {
-            Boolean res = isValid.right().value();
-            if (!res) {
+            if (!Boolean.TRUE.equals(isValid.right().value())) {
                 log.debug("validate and update property value has failed with value: {}", property.getValue());
                 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(
                     DaoStatusConverter.convertJanusGraphStatusToStorageStatus(JanusGraphOperationStatus.ILLEGAL_ARGUMENT)));
@@ -2199,7 +2317,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         if (!isInput) {
             ImmutablePair<String, Boolean> pair = propertyOperation
                 .validateAndUpdateRules(propertyType, ((ComponentInstanceProperty) property).getRules(), innerType, allDataTypes, true);
-            if (pair.getRight() != null && pair.getRight() == false) {
+            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))));
@@ -2208,6 +2326,58 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         return Either.left(newValue);
     }
 
+    private <T extends AttributeDefinition> Either<String, ResponseFormat> updateAttributeObjectValue(final T attribute) {
+        final Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> allDataTypesEither = dataTypeCache.getAll();
+        if (allDataTypesEither.isRight()) {
+            JanusGraphOperationStatus status = allDataTypesEither.right().value();
+            BeEcompErrorManager.getInstance()
+                .logInternalFlowError("UpdatePropertyValueOnComponentInstance", "Failed to update attribute value on instance. Status is " + status,
+                    ErrorSeverity.ERROR);
+            return Either.right(componentsUtils
+                .getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status))));
+        }
+        String innerType = null;
+        final String attributeType = attribute.getType();
+        final ToscaPropertyType type = ToscaPropertyType.isValidType(attributeType);
+        log.debug("The type of the attribute {} is {}", attribute.getUniqueId(), attributeType);
+
+        if (type == ToscaPropertyType.LIST || type == ToscaPropertyType.MAP) {
+            final SchemaDefinition def = attribute.getSchema();
+            if (def == null) {
+                log.debug("Schema doesn't exists for attribute of type {}", type);
+                return Either
+                    .right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(StorageOperationStatus.INVALID_VALUE)));
+            }
+            PropertyDataDefinition propDef = def.getProperty();
+            if (propDef == null) {
+                log.debug("Property in Schema Definition inside attribute of type {} doesn't exist", type);
+                return Either
+                    .right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(StorageOperationStatus.INVALID_VALUE)));
+            }
+            innerType = propDef.getType();
+        }
+
+        // Specific Update Logic
+        String newValue = attribute.getValue();
+
+        final Either<Object, Boolean> isValid = attributeOperation
+            .validateAndUpdateAttributeValue(attributeType, attribute.getValue(), true, innerType, allDataTypesEither.left().value());
+        if (isValid.isRight()) {
+            final Boolean res = isValid.right().value();
+            if (!Boolean.TRUE.equals(res)) {
+                log.debug("validate and update attribute value has failed with value: {}", attribute.getValue());
+                throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(
+                    DaoStatusConverter.convertJanusGraphStatusToStorageStatus(JanusGraphOperationStatus.ILLEGAL_ARGUMENT)));
+            }
+        } else {
+            final Object object = isValid.left().value();
+            if (object != null) {
+                newValue = object.toString();
+            }
+        }
+        return Either.left(newValue);
+    }
+
     private <T extends PropertyDefinition> void validateToscaGetFunction(T property) {
         if (property.getToscaGetFunctionType() == ToscaGetFunctionType.GET_INPUT) {
             final List<GetInputValueDataDefinition> getInputValues = property.getGetInputValues();
@@ -2270,7 +2440,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         Component containerComponent = getResourceResult.left().value();
 
         if (!ComponentValidationUtils.canWorkOnComponent(containerComponent, userId)) {
-            if (containerComponent.isArchived()) {
+            if (Boolean.TRUE.equals(containerComponent.isArchived())) {
                 log.info("Component is archived. Component id: {}", componentId);
                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_IS_ARCHIVED, containerComponent.getName()));
             }
@@ -2513,7 +2683,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
             ActionStatus actionStatus = ActionStatus.CONTAINER_CANNOT_CONTAIN_COMPONENT_IN_STATE;
             throw new ByActionStatusComponentException(actionStatus, containerComponent.getComponentType().toString(), resourceCurrState.toString());
         }
-        if (component.isArchived() == true) {
+        if (Boolean.TRUE.equals(component.isArchived())) {
             ActionStatus actionStatus = ActionStatus.COMPONENT_IS_ARCHIVED;
             throw new ByActionStatusComponentException(actionStatus, component.getName());
         }
@@ -2553,7 +2723,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
             resultOp = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse
                 (componentExistsRes.right().value()), resourceId));
             return resultOp;
-        } else if (!componentExistsRes.left().value()) {
+        } else if (!Boolean.TRUE.equals(componentExistsRes.left().value())) {
             log.debug("The resource {} not found ", resourceId);
             resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, resourceId));
             return resultOp;
@@ -2636,7 +2806,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                 log.debug("Failed to validate existing of the component {}. Status is {} ", resourceId, errorStatus);
                 throw new ByActionStatusComponentException(
                     componentsUtils.convertFromStorageResponse(errorStatus), resourceId);
-            } else if (!componentExistsRes.left().value()) {
+            } else if (!Boolean.TRUE.equals(componentExistsRes.left().value())) {
                 log.debug("The resource {} not found ", resourceId);
                 throw new ByActionStatusComponentException(ActionStatus.RESOURCE_NOT_FOUND, resourceId);
             }
@@ -3325,7 +3495,8 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         Either<ComponentInstanceAttribute, ResponseFormat> resultOp = null;
         validateUserExists(userId);
         if (componentTypeEnum == null) {
-            BeEcompErrorManager.getInstance().logInvalidInputError("createOrUpdateAttributeValue", INVALID_COMPONENT_TYPE, ErrorSeverity.INFO);
+            BeEcompErrorManager.getInstance()
+                .logInvalidInputError("createOrUpdateAttributeValueForCopyPaste", INVALID_COMPONENT_TYPE, ErrorSeverity.INFO);
             resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.NOT_ALLOWED));
             return resultOp;
         }
index 5515400..7816d3d 100644 (file)
@@ -35,7 +35,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.responses.ApiResponse;
 import io.swagger.v3.oas.annotations.servers.Server;
 import io.swagger.v3.oas.annotations.tags.Tag;
-import io.swagger.v3.oas.annotations.tags.Tags;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Type;
@@ -111,7 +110,7 @@ import org.springframework.stereotype.Controller;
  */
 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
 @Path("/v1/catalog")
-@Tags({@Tag(name = "SDCE-2 APIs")})
+@Tag(name = "SDCE-2 APIs")
 @Server(url = "/sdc2/rest")
 @Controller
 public class ComponentInstanceServlet extends AbstractValidationsServlet {
@@ -121,6 +120,7 @@ public class ComponentInstanceServlet extends AbstractValidationsServlet {
     private static final String GET_GROUP_ARTIFACT_BY_ID_UNEXPECTED_EXCEPTION = "getGroupArtifactById unexpected exception";
     private static final String GET_START_HANDLE_REQUEST_OF = "(GET) Start handle request of {}";
     private static final String START_HANDLE_REQUEST_OF_UPDATE_RESOURCE_INSTANCE_PROPERTY_RECEIVED_PROPERTY_IS = "Start handle request of updateResourceInstanceProperty. Received property is {}";
+    private static final String START_HANDLE_REQUEST_OF_UPDATE_RESOURCE_INSTANCE_ATTRIBUTE_RECEIVED_ATTRIBUTE_IS = "Start handle request of updateResourceInstanceAttribute. Received attribute is {}";
     private static final String UPDATE_RESOURCE_INSTANCE = "Update Resource Instance";
     private static final String RESOURCE_INSTANCE_UPDATE_RESOURCE_INSTANCE = "Resource Instance - updateResourceInstance";
     private static final String UPDATE_RESOURCE_INSTANCE_WITH_EXCEPTION = "update resource instance with exception";
@@ -641,10 +641,10 @@ public class ComponentInstanceServlet extends AbstractValidationsServlet {
      * @return
      */
     @POST
-    @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}/attribute")
+    @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}/attributes")
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    @Operation(description = "Update resource instance attribute", method = "POST", summary = "Returns updated resource instance attribute", responses = {
+    @Operation(description = "Update resource instance attribute", method = "POST", summary = "Returns updated resource instance property", responses = {
         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
         @ApiResponse(responseCode = "201", description = "Resource instance created"),
         @ApiResponse(responseCode = "403", description = "Restricted operation"),
@@ -655,45 +655,52 @@ public class ComponentInstanceServlet extends AbstractValidationsServlet {
                                                         ComponentTypeEnum.RESOURCE_PARAM_NAME,
                                                         ComponentTypeEnum.SERVICE_PARAM_NAME})) @PathParam("containerComponentType") final String containerComponentType,
                                                     @Parameter(description = "resource instance id") @PathParam("componentInstanceId") final String componentInstanceId,
-                                                    @Parameter(description = "id of user initiating the operation") @HeaderParam(value = Constants.USER_ID_HEADER) String userId,
-                                                    @Context final HttpServletRequest request) throws IOException {
-        String url = request.getMethod() + " " + request.getRequestURI();
+                                                    @Parameter(description = "id of user initiating the operation") @HeaderParam(value = Constants.USER_ID_HEADER) final String userId,
+                                                    @Context final HttpServletRequest request,
+                                                    @Parameter(description = "Component Instance Properties JSON Array", required = true) final String componentInstanceAttributesJsonArray) {
+        final String url = request.getMethod() + " " + request.getRequestURI();
         log.debug(START_HANDLE_REQUEST_OF, url);
-        loggerSupportability
-            .log(LoggerSupportabilityActions.UPDATE_RESOURCE, StatusCode.STARTED, "Starting to update Resource Instance Attribute for component {} ",
-                componentId + " by " + userId);
-        try {
-            Wrapper<ResponseFormat> errorWrapper = new Wrapper<>();
-            Wrapper<String> dataWrapper = new Wrapper<>();
-            Wrapper<ComponentInstanceProperty> attributeWrapper = new Wrapper<>();
-            Wrapper<ComponentInstanceBusinessLogic> blWrapper = new Wrapper<>();
-            validateInputStream(request, dataWrapper, errorWrapper);
-            if (errorWrapper.isEmpty()) {
-                validateClassParse(dataWrapper.getInnerElement(), attributeWrapper, () -> ComponentInstanceProperty.class, errorWrapper);
-            }
-            if (errorWrapper.isEmpty()) {
-                validateComponentInstanceBusinessLogic(request, containerComponentType, blWrapper, errorWrapper);
-            }
-            if (errorWrapper.isEmpty()) {
-                ComponentInstanceBusinessLogic componentInstanceLogic = blWrapper.getInnerElement();
-                ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
-                log.debug("Start handle request of ComponentInstanceAttribute. Received attribute is {}", attributeWrapper.getInnerElement());
-                Either<ComponentInstanceProperty, ResponseFormat> eitherAttribute = componentInstanceLogic
-                    .createOrUpdateAttributeValue(componentTypeEnum, componentId, componentInstanceId, attributeWrapper.getInnerElement(), userId);
-                if (eitherAttribute.isRight()) {
-                    errorWrapper.setInnerElement(eitherAttribute.right().value());
-                } else {
-                    attributeWrapper.setInnerElement(eitherAttribute.left().value());
-                }
+        loggerSupportability.log(LoggerSupportabilityActions.UPDATE_COMPONENT_INSTANCE, StatusCode.STARTED,
+            "Starting to update Resource Instance Attributes for component {} ", componentId + " by " + userId);
+        final Wrapper<ResponseFormat> errorWrapper = new Wrapper<>();
+        List<ComponentInstanceAttribute> attributesToUpdate = new ArrayList<>();
+        if (errorWrapper.isEmpty()) {
+            final Either<List<ComponentInstanceAttribute>, ResponseFormat> attributesToUpdateEither = convertMultipleAttributes(
+                componentInstanceAttributesJsonArray);
+            if (attributesToUpdateEither.isRight()) {
+                errorWrapper.setInnerElement(attributesToUpdateEither.right().value());
+            } else {
+                attributesToUpdate = attributesToUpdateEither.left().value();
             }
-            loggerSupportability
-                .log(LoggerSupportabilityActions.UPDATE_RESOURCE, StatusCode.COMPLETE, "Ended update Resource Instance Attribute for component {} ",
-                    componentId + " by " + userId);
-            return buildResponseFromElement(errorWrapper, attributeWrapper);
-        } catch (Exception e) {
-            log.error(CREATE_AND_ASSOCIATE_RI_FAILED_WITH_EXCEPTION, e.getMessage(), e);
-            throw e;
         }
+        if (!errorWrapper.isEmpty()) {
+            return buildErrorResponse(errorWrapper.getInnerElement());
+        }
+        log.debug(START_HANDLE_REQUEST_OF_UPDATE_RESOURCE_INSTANCE_ATTRIBUTE_RECEIVED_ATTRIBUTE_IS, attributesToUpdate);
+        final ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
+        if (componentInstanceBusinessLogic == null) {
+            log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
+            return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
+        }
+        final Either<List<ComponentInstanceAttribute>, ResponseFormat> actionResponse = componentInstanceBusinessLogic
+            .createOrUpdateAttributeValues(componentTypeEnum, componentId, componentInstanceId, attributesToUpdate, userId);
+        if (actionResponse.isRight()) {
+            return buildErrorResponse(actionResponse.right().value());
+        }
+        final List<ComponentInstanceAttribute> resourceInstanceAttributes = actionResponse.left().value();
+        final ObjectMapper mapper = new ObjectMapper();
+        String result;
+        loggerSupportability.log(LoggerSupportabilityActions.UPDATE_COMPONENT_INSTANCE, StatusCode.COMPLETE,
+            "Ended update Resource Instance Attributes for component {} ", componentId + " by " + userId);
+        try {
+            result = mapper.writeValueAsString(resourceInstanceAttributes);
+        } catch (JsonProcessingException e) {
+            log.error(UPDATE_RESOURCE_INSTANCE_WITH_EXCEPTION, e.getMessage(), e);
+            throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
+        }
+        loggerSupportability.log(LoggerSupportabilityActions.UPDATE_COMPONENT_INSTANCE, StatusCode.COMPLETE,
+            "Ended update Resource Instance Attributes for component {} ", componentId + " by user " + userId);
+        return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result);
     }
 
     @DELETE
@@ -1258,6 +1265,18 @@ public class ComponentInstanceServlet extends AbstractValidationsServlet {
         return Either.left(Arrays.asList(convertStatus.left().value()));
     }
 
+    private Either<List<ComponentInstanceAttribute>, ResponseFormat> convertMultipleAttributes(final String dataList) {
+        if (StringUtils.isEmpty(dataList)) {
+            return Either.right(getComponentsUtils().getResponseFormat(ActionStatus.MISSING_BODY));
+        }
+        final Either<ComponentInstanceAttribute[], ResponseFormat> convertStatus = getComponentsUtils().
+            convertJsonToObjectUsingObjectMapper(dataList, new User(), ComponentInstanceAttribute[].class, null, ComponentTypeEnum.RESOURCE_INSTANCE);
+        if (convertStatus.isRight()) {
+            return Either.right(convertStatus.right().value());
+        }
+        return Either.left(Arrays.asList(convertStatus.left().value()));
+    }
+
     private Either<List<ComponentInstanceInput>, ResponseFormat> convertMultipleInputs(String dataList) {
         if (StringUtils.isEmpty(dataList)) {
             return Either.right(getComponentsUtils().getResponseFormat(ActionStatus.MISSING_BODY));
index 0adb90d..f2e8c83 100644 (file)
@@ -315,4 +315,37 @@ public class AttributeOperation extends AbstractOperation {
     private void updateAttributeValue(final AttributeDataDefinition attributeDefinition, final JsonElement jsonElement) {
         attributeDefinition.set_default(jsonElement);
     }
+
+    public Either<Object, Boolean> validateAndUpdateAttributeValue(final String attributeType,
+                                                                   final String value,
+                                                                   final boolean isValidate,
+                                                                   final String innerType,
+                                                                   final Map<String, DataTypeDefinition> dataTypes) {
+        log.trace("Going to validate attribute value and its type. type = {}, value = {}", attributeType, value);
+        final ToscaPropertyType type = getType(attributeType);
+        if (isValidate) {
+            if (type == null) {
+                final DataTypeDefinition dataTypeDefinition = dataTypes.get(attributeType);
+                final ImmutablePair<JsonElement, Boolean> validateResult =
+                    dataTypeValidatorConverter.validateAndUpdate(value, dataTypeDefinition, dataTypes);
+                if (Boolean.FALSE.equals(validateResult.right)) {
+                    log.debug(THE_VALUE_OF_ATTRIBUTE_FROM_TYPE_IS_INVALID, value, attributeType);
+                    return Either.right(false);
+                }
+                return Either.left(getValueFromJsonElement(validateResult.left));
+            }
+            log.trace("before validating property type {}", attributeType);
+            if (!isValidValue(type, value, innerType, dataTypes)) {
+                log.debug(THE_VALUE_OF_ATTRIBUTE_FROM_TYPE_IS_INVALID, value, type);
+                return Either.right(false);
+            }
+        }
+        Object convertedValue = value;
+        if (!isEmptyValue(value) && isValidate) {
+            PropertyValueConverter converter = type.getConverter();
+            convertedValue = converter.convert(value, innerType, dataTypes);
+        }
+        return Either.left(convertedValue);
+    }
+
 }
index d7db8f3..f97f849 100644 (file)
@@ -198,7 +198,6 @@ export class AttributesOutputsComponent {
         event.preventDefault();
         this.showUnsavedChangesAlert().then(() => {
           this.$state.go(toState, toParams);
-        }, () => {
         });
       }
     });
@@ -390,7 +389,6 @@ export class AttributesOutputsComponent {
       this.attributeOutputTabs.triggerTabChange(this.currentMainTab.title);
       this.showUnsavedChangesAlert().then(() => {
         this.attributeOutputTabs.selectTab(this.attributeOutputTabs.tabs.find((tab) => tab.title === event.title));
-      }, () => {
       });
       return;
     }
@@ -451,7 +449,7 @@ export class AttributesOutputsComponent {
       let request;
       let handleSuccess, handleError;
       if (this.isAttributesTabSelected) {
-        this.changedData.map((changedAttrib) => {
+        const changedAttribs = this.changedData.map((changedAttrib) => {
           changedAttrib = <AttributeFEModel>changedAttrib;
           const attribBE = new AttributeBEModel(changedAttrib);
           attribBE.toscaPresentation = new ToscaPresentationData();
@@ -461,6 +459,28 @@ export class AttributesOutputsComponent {
           delete attribBE.origName;
           return attribBE;
         });
+
+        if (this.selectedInstanceData instanceof ComponentInstance) {
+          if (this.isSelf()) {
+            console.log("changedAttribs", changedAttribs);
+            request = this.topologyTemplateService.updateServiceAttributes(this.component.uniqueId, _.map(changedAttribs, cp => {
+              delete cp.constraints;
+              return cp;
+            }));
+          } else {
+            request = this.componentInstanceServiceNg2
+            .updateInstanceAttributes(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedAttribs);
+          }
+          handleSuccess = (response) => {
+            // reset each changed attribute with new value and remove it from changed attributes list
+            response.forEach((resAttrib) => {
+              const changedAttrib = <AttributeFEModel>this.changedData.shift();
+              this.attributesUtils.resetAttributeValue(changedAttrib, resAttrib.value);
+            });
+            resolve(response);
+            console.log("updated instance attributes: ", response);
+          };
+        }
       } else if (this.isOutputsTabSelected) {
         const changedOutputs: OutputBEModel[] = this.changedData.map((changedOutput) => {
           changedOutput = <OutputFEModel>changedOutput;
@@ -468,8 +488,7 @@ export class AttributesOutputsComponent {
           outputBE.defaultValue = changedOutput.getJSONDefaultValue();
           return outputBE;
         });
-        request = this.componentServiceNg2
-        .updateComponentOutputs(this.component, changedOutputs);
+        request = this.componentServiceNg2.updateComponentOutputs(this.component, changedOutputs);
         handleSuccess = (response) => {
           // reset each changed attribute with new value and remove it from changed attributes list
           response.forEach((resOutput) => {
@@ -478,23 +497,24 @@ export class AttributesOutputsComponent {
             changedOutput.required = resOutput.required;
           });
         }
-        this.savingChangedData = true;
-        request.subscribe(
-            (response) => {
-              this.savingChangedData = false;
-              handleSuccess && handleSuccess(response);
-              this.updateHasChangedData();
-              resolve(response);
-            },
-            (error) => {
-              this.savingChangedData = false;
-              handleError && handleError(error);
-              this.updateHasChangedData();
-              reject(error);
-            }
-        );
       }
 
+      this.savingChangedData = true;
+      request.subscribe(
+          (response) => {
+            this.savingChangedData = false;
+            handleSuccess && handleSuccess(response);
+            this.updateHasChangedData();
+            resolve(response);
+          },
+          (error) => {
+            this.savingChangedData = false;
+            handleError && handleError(error);
+            this.updateHasChangedData();
+            reject(error);
+          }
+      );
+
     });
   };