Implement Attributes/Outputs BE (part 2)
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / AttributeBusinessLogic.java
index c20a2b3..a44ed3c 100644 (file)
@@ -7,9 +7,9 @@
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 package org.openecomp.sdc.be.components.impl;
 
 import fj.data.Either;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.openecomp.sdc.be.config.BeEcompErrorManager;
 import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
+import org.openecomp.sdc.be.model.AttributeDefinition;
+import org.openecomp.sdc.be.model.Component;
+import org.openecomp.sdc.be.model.ComponentParametersView;
 import org.openecomp.sdc.be.model.DataTypeDefinition;
-import org.openecomp.sdc.be.model.PropertyDefinition;
+import org.openecomp.sdc.be.model.InterfaceDefinition;
 import org.openecomp.sdc.be.model.Resource;
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
@@ -36,40 +47,35 @@ import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
+import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
+import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter;
 import org.openecomp.sdc.common.log.wrappers.Logger;
 import org.openecomp.sdc.exception.ResponseFormat;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
 
 /**
  * This class holds the business logic relevant for attributes manipulation.
- * 
- * @author mshitrit
  *
+ * @author mshitrit
  */
-@Component("attributeBusinessLogic")
+@org.springframework.stereotype.Component("attributeBusinessLogic")
 public class AttributeBusinessLogic extends BaseBusinessLogic {
 
     private static final String CREATE_ATTRIBUTE = "CreateAttribute";
     private static final String UPDATE_ATTRIBUTE = "UpdateAttribute";
     private static final String DELETE_ATTRIBUTE = "DeleteAttribute";
 
-    private static final Logger log = Logger.getLogger(AttributeBusinessLogic.class.getName());
+    private static final Logger log = Logger.getLogger(AttributeBusinessLogic.class);
     private static final String FAILED_TO_LOCK_COMPONENT_ERROR = "Failed to lock component {}. Error - {}";
 
     @Autowired
     public AttributeBusinessLogic(IElementOperation elementDao,
-        IGroupOperation groupOperation,
-        IGroupInstanceOperation groupInstanceOperation,
-        IGroupTypeOperation groupTypeOperation,
-        InterfaceOperation interfaceOperation,
-        InterfaceLifecycleOperation interfaceLifecycleTypeOperation,
-        ArtifactsOperations artifactToscaOperation) {
+                                  IGroupOperation groupOperation,
+                                  IGroupInstanceOperation groupInstanceOperation,
+                                  IGroupTypeOperation groupTypeOperation,
+                                  InterfaceOperation interfaceOperation,
+                                  InterfaceLifecycleOperation interfaceLifecycleTypeOperation,
+                                  ArtifactsOperations artifactToscaOperation) {
         super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation,
             interfaceOperation, interfaceLifecycleTypeOperation, artifactToscaOperation);
     }
@@ -82,13 +88,16 @@ public class AttributeBusinessLogic extends BaseBusinessLogic {
      * @param userId
      * @return AttributeDefinition if created successfully Or ResponseFormat
      */
-    public Either<PropertyDefinition, ResponseFormat> createAttribute(String resourceId, PropertyDefinition newAttributeDef, String userId) {
-        Either<PropertyDefinition, ResponseFormat> result = null;
-        validateUserExists(userId, "create Attribute", false);
+    public Either<AttributeDefinition, ResponseFormat> createAttribute(String resourceId,
+                                                                       AttributeDefinition newAttributeDef,
+                                                                       String userId) {
+        Either<AttributeDefinition, ResponseFormat> result = null;
+        validateUserExists(userId);
 
         StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource);
         if (lockResult != StorageOperationStatus.OK) {
-            BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId);
+            BeEcompErrorManager.getInstance()
+                .logBeFailedLockObjectError(CREATE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId);
             log.info(FAILED_TO_LOCK_COMPONENT_ERROR, resourceId, lockResult);
             return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
         }
@@ -108,26 +117,28 @@ public class AttributeBusinessLogic extends BaseBusinessLogic {
 
             // verify attribute does not exist in resource
             if (isAttributeExist(resource.getAttributes(), resourceId, newAttributeDef.getName())) {
-                return Either.right(componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_ALREADY_EXIST, newAttributeDef.getName()));
-            }
-            Either<Map<String, DataTypeDefinition>, ResponseFormat> eitherAllDataTypes = getAllDataTypes(applicationDataTypeCache);
-            if (eitherAllDataTypes.isRight()) {
-                return Either.right(eitherAllDataTypes.right().value());
+                return Either.right(
+                    componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_ALREADY_EXIST, newAttributeDef.getName()));
             }
+            Map<String, DataTypeDefinition> eitherAllDataTypes = getAllDataTypes(applicationDataTypeCache);
             // validate property default values
-            Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue(newAttributeDef, eitherAllDataTypes.left().value());
+            Either<Boolean, ResponseFormat> defaultValuesValidation = validateAttributeDefaultValue(newAttributeDef,
+                eitherAllDataTypes);
             if (defaultValuesValidation.isRight()) {
                 return Either.right(defaultValuesValidation.right().value());
             }
 
-            handleDefaultValue(newAttributeDef, eitherAllDataTypes.left().value());
+            handleAttributeDefaultValue(newAttributeDef, eitherAllDataTypes);
 
             // add the new attribute to resource on graph
-            // need to get StorageOpaerationStatus and convert to ActionStatus from
+            // need to get StorageOperationStatus and convert to ActionStatus from
             // componentsUtils
-            Either<PropertyDefinition, StorageOperationStatus> either = toscaOperationFacade.addAttributeOfResource(resource, newAttributeDef);
+            Either<AttributeDefinition, StorageOperationStatus> either = toscaOperationFacade
+                .addAttributeOfResource(resource, newAttributeDef);
             if (either.isRight()) {
-                result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(either.right().value()), resource.getName()));
+                result = Either.right(componentsUtils
+                    .getResponseFormat(componentsUtils.convertFromStorageResponse(either.right().value()),
+                        resource.getName()));
                 return result;
             }
             result = Either.left(either.left().value());
@@ -137,13 +148,76 @@ public class AttributeBusinessLogic extends BaseBusinessLogic {
             commitOrRollback(result);
             graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource);
         }
+    }
+
+    private Either<Boolean, ResponseFormat> validateAttributeDefaultValue(final AttributeDefinition attributeDefinition,
+                                                                          final Map<String, DataTypeDefinition> dataTypes) {
+
+        if (!attributeOperation.isAttributeTypeValid(attributeDefinition)) {
+            log.info("Invalid type for attribute '{}' type '{}'", attributeDefinition.getName(),
+                attributeDefinition.getType());
+            final ResponseFormat responseFormat = componentsUtils
+                .getResponseFormat(ActionStatus.INVALID_PROPERTY_TYPE, attributeDefinition
+                    .getType(), attributeDefinition.getName());
+            return Either.right(responseFormat);
+        }
+        String type = attributeDefinition.getType();
+        String innerType = null;
+        if (type.equals(ToscaPropertyType.LIST.getType()) || type.equals(ToscaPropertyType.MAP.getType())) {
+            final ImmutablePair<String, Boolean> propertyInnerTypeValid = attributeOperation.isAttributeInnerTypeValid(
+                attributeDefinition, dataTypes);
+            innerType = propertyInnerTypeValid.getLeft();
+            if (!Boolean.TRUE.equals(propertyInnerTypeValid.getRight())) {
+                log.info("Invalid inner type for attribute '{}' type '{}', dataTypeCount '{}'",
+                    attributeDefinition.getName(), attributeDefinition.getType(), dataTypes.size());
+                final ResponseFormat responseFormat = componentsUtils
+                    .getResponseFormat(ActionStatus.INVALID_PROPERTY_INNER_TYPE, innerType,
+                        attributeDefinition.getName());
+                return Either.right(responseFormat);
+            }
+        }
+        if (!attributeOperation.isAttributeDefaultValueValid(attributeDefinition, dataTypes)) {
+            log.info("Invalid default value for attribute '{}' type '{}'", attributeDefinition.getName(),
+                attributeDefinition.getType());
+            ResponseFormat responseFormat;
+            if (type.equals(ToscaPropertyType.LIST.getType()) || type.equals(ToscaPropertyType.MAP.getType())) {
+                responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_COMPLEX_DEFAULT_VALUE,
+                    attributeDefinition.getName(), type, innerType,
+                    (String) attributeDefinition.get_default());
+            } else {
+                responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_DEFAULT_VALUE,
+                    attributeDefinition.getName(), type, (String) attributeDefinition.get_default());
+            }
+            return Either.right(responseFormat);
+
+        }
+        return Either.left(true);
+    }
 
+    private void handleAttributeDefaultValue(final AttributeDefinition newAttributeDefinition,
+                                             final Map<String, DataTypeDefinition> dataTypes) {
+        final ToscaPropertyType type = ToscaPropertyType.isValidType(newAttributeDefinition.getType());
+        final PropertyValueConverter converter = type.getConverter();
+        // get inner type
+        String innerType = null;
+        final SchemaDefinition schema = newAttributeDefinition.getSchema();
+        if (schema != null) {
+            final PropertyDataDefinition prop = schema.getProperty();
+            if (schema.getProperty() != null) {
+                innerType = prop.getType();
+            }
+        }
+        if (newAttributeDefinition.get_default() != null) {
+            newAttributeDefinition.set_default(converter
+                .convert((String) newAttributeDefinition.get_default(), innerType, dataTypes));
+        }
     }
 
-    private boolean isAttributeExist(List<PropertyDefinition> attributes, String resourceUid, String propertyName) {
+    private boolean isAttributeExist(List<AttributeDefinition> attributes, String resourceUid, String propertyName) {
         boolean isExist = false;
         if (attributes != null) {
-            isExist = attributes.stream().anyMatch(p -> Objects.equals(p.getName(), propertyName) && Objects.equals(p.getParentUniqueId(), resourceUid));
+            isExist = attributes.stream().anyMatch(
+                p -> Objects.equals(p.getName(), propertyName) && Objects.equals(p.getOwnerId(), resourceUid));
         }
         return isExist;
 
@@ -155,9 +229,10 @@ public class AttributeBusinessLogic extends BaseBusinessLogic {
      * @param userId
      * @return
      */
-    public Either<PropertyDefinition, ResponseFormat> getAttribute(String resourceId, String attributeId, String userId) {
+    public Either<AttributeDefinition, ResponseFormat> getAttribute(String resourceId, String attributeId,
+                                                                    String userId) {
 
-        validateUserExists(userId, "get Attribute", false);
+        validateUserExists(userId);
 
         // Get the resource from DB
         Either<Resource, StorageOperationStatus> status = toscaOperationFacade.getToscaElement(resourceId);
@@ -166,15 +241,16 @@ public class AttributeBusinessLogic extends BaseBusinessLogic {
         }
         Resource resource = status.left().value();
 
-        List<PropertyDefinition> attributes = resource.getAttributes();
+        List<AttributeDefinition> attributes = resource.getAttributes();
         if (attributes == null) {
             return Either.right(componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_NOT_FOUND, ""));
         } else {
             // verify attribute exist in resource
-            Optional<PropertyDefinition> optionalAtt = attributes.stream().filter(att -> att.getUniqueId().equals(attributeId) && att.getParentUniqueId().equals(resourceId)).findAny();
-            return optionalAtt.<Either<PropertyDefinition, ResponseFormat>>map(Either::left).orElseGet(() -> Either.right(componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_NOT_FOUND, "")));
+            Optional<AttributeDefinition> optionalAtt = attributes.stream().filter(att ->
+                att.getUniqueId().equals(attributeId)).findAny();
+            return optionalAtt.<Either<AttributeDefinition, ResponseFormat>>map(Either::left).orElseGet(() ->
+                Either.right(componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_NOT_FOUND, "")));
         }
-
     }
 
     /**
@@ -186,12 +262,14 @@ public class AttributeBusinessLogic extends BaseBusinessLogic {
      * @param userId
      * @return
      */
-    public Either<PropertyDefinition, ResponseFormat> updateAttribute(String resourceId, String attributeId, PropertyDefinition newAttDef, String userId) {
-        Either<PropertyDefinition, ResponseFormat> result = null;
+    public Either<AttributeDefinition, ResponseFormat> updateAttribute(String resourceId, String attributeId,
+                                                                       AttributeDefinition newAttDef, String userId) {
+        Either<AttributeDefinition, ResponseFormat> result = null;
 
         StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource);
         if (lockResult != StorageOperationStatus.OK) {
-            BeEcompErrorManager.getInstance().logBeFailedLockObjectError(UPDATE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId);
+            BeEcompErrorManager.getInstance()
+                .logBeFailedLockObjectError(UPDATE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId);
             log.info(FAILED_TO_LOCK_COMPONENT_ERROR, resourceId, lockResult);
             return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
         }
@@ -209,34 +287,38 @@ public class AttributeBusinessLogic extends BaseBusinessLogic {
             }
 
             // verify attribute exist in resource
-            Either<PropertyDefinition, ResponseFormat> eitherAttribute = getAttribute(resourceId, attributeId, userId);
+            Either<AttributeDefinition, ResponseFormat> eitherAttribute = getAttribute(resourceId, attributeId, userId);
             if (eitherAttribute.isRight()) {
                 return Either.right(eitherAttribute.right().value());
             }
-            Either<Map<String, DataTypeDefinition>, ResponseFormat> eitherAllDataTypes = getAllDataTypes(applicationDataTypeCache);
-            if (eitherAllDataTypes.isRight()) {
-                return Either.right(eitherAllDataTypes.right().value());
-            }
+            Map<String, DataTypeDefinition> eitherAllDataTypes = getAllDataTypes(applicationDataTypeCache);
 
             // validate attribute default values
-            Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue(newAttDef, eitherAllDataTypes.left().value());
+            Either<Boolean, ResponseFormat> defaultValuesValidation = validateAttributeDefaultValue(newAttDef,
+                eitherAllDataTypes);
             if (defaultValuesValidation.isRight()) {
                 return Either.right(defaultValuesValidation.right().value());
             }
-            // add the new property to resource on graph
 
-            StorageOperationStatus validateAndUpdateAttribute = propertyOperation.validateAndUpdateProperty(newAttDef, eitherAllDataTypes.left().value());
+            // add the new property to resource on graph
+            StorageOperationStatus validateAndUpdateAttribute = attributeOperation
+                .validateAndUpdateAttribute(newAttDef, eitherAllDataTypes);
             if (validateAndUpdateAttribute != StorageOperationStatus.OK) {
-                log.debug("Problem while updating attribute with id {}. Reason - {}", attributeId, validateAndUpdateAttribute);
-                result = Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(validateAndUpdateAttribute), resource.getName()));
+                log.debug("Problem while updating attribute with id {}. Reason - {}", attributeId,
+                    validateAndUpdateAttribute);
+                result = Either.right(componentsUtils
+                    .getResponseFormatByResource(componentsUtils.convertFromStorageResponse(validateAndUpdateAttribute),
+                        resource.getName()));
             }
 
-
-            Either<PropertyDefinition, StorageOperationStatus> eitherAttUpdate = toscaOperationFacade.updateAttributeOfResource(resource, newAttDef);
+            Either<AttributeDefinition, StorageOperationStatus> eitherAttUpdate = toscaOperationFacade
+                .updateAttributeOfResource(resource, newAttDef);
 
             if (eitherAttUpdate.isRight()) {
-                log.debug("Problem while updating attribute with id {}. Reason - {}", attributeId, eitherAttUpdate.right().value());
-                result = Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(eitherAttUpdate.right().value()), resource.getName()));
+                log.debug("Problem while updating attribute with id {}. Reason - {}", attributeId,
+                    eitherAttUpdate.right().value());
+                result = Either.right(componentsUtils.getResponseFormatByResource(
+                    componentsUtils.convertFromStorageResponse(eitherAttUpdate.right().value()), resource.getName()));
                 return result;
             }
 
@@ -257,15 +339,17 @@ public class AttributeBusinessLogic extends BaseBusinessLogic {
      * @param userId
      * @return
      */
-    public Either<PropertyDefinition, ResponseFormat> deleteAttribute(String resourceId, String attributeId, String userId) {
+    public Either<AttributeDefinition, ResponseFormat> deleteAttribute(String resourceId, String attributeId,
+                                                                       String userId) {
 
-        Either<PropertyDefinition, ResponseFormat> result = null;
+        Either<AttributeDefinition, ResponseFormat> result = null;
 
-        validateUserExists(userId, "delete Attribute", false);
+        validateUserExists(userId);
 
         StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource);
         if (lockResult != StorageOperationStatus.OK) {
-            BeEcompErrorManager.getInstance().logBeFailedLockObjectError(DELETE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId);
+            BeEcompErrorManager.getInstance()
+                .logBeFailedLockObjectError(DELETE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId);
             log.info(FAILED_TO_LOCK_COMPONENT_ERROR, resourceId, lockResult);
             return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
         }
@@ -284,16 +368,20 @@ public class AttributeBusinessLogic extends BaseBusinessLogic {
             }
 
             // verify attribute exist in resource
-            Either<PropertyDefinition, ResponseFormat> eitherAttributeExist = getAttribute(resourceId, attributeId, userId);
+            Either<AttributeDefinition, ResponseFormat> eitherAttributeExist = getAttribute(resourceId, attributeId,
+                userId);
             if (eitherAttributeExist.isRight()) {
                 return Either.right(eitherAttributeExist.right().value());
             }
             String attributeName = eitherAttributeExist.left().value().getName();
 
             // delete attribute of resource from graph
-            StorageOperationStatus eitherAttributeDelete = toscaOperationFacade.deleteAttributeOfResource(resource, attributeName);
+            StorageOperationStatus eitherAttributeDelete = toscaOperationFacade
+                .deleteAttributeOfResource(resource, attributeName);
             if (eitherAttributeDelete != StorageOperationStatus.OK) {
-                result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(eitherAttributeDelete), resource.getName()));
+                result = Either.right(componentsUtils
+                    .getResponseFormat(componentsUtils.convertFromStorageResponse(eitherAttributeDelete),
+                        resource.getName()));
                 return result;
             }
 
@@ -304,4 +392,54 @@ public class AttributeBusinessLogic extends BaseBusinessLogic {
             graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource);
         }
     }
+
+    public Either<List<AttributeDefinition>, ResponseFormat> getAttributesList(final String componentId,
+                                                                               final String userId) {
+        validateUserExists(userId);
+
+        // Get the resource from DB
+        final ComponentParametersView filter = new ComponentParametersView(true);
+        filter.setIgnoreAttributes(false);
+        final Either<Component, StorageOperationStatus> status = toscaOperationFacade.getToscaElement(componentId, filter);
+        if (status.isRight()) {
+            return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
+        }
+
+        return Either.left(status.left().value().getAttributes());
+    }
+
+    public boolean isAttributeUsedByOperation(Component component,
+                                              AttributeDefinition propertyDefinitionEntry) {
+        // TODO - do we need this one
+        return false;
+
+//        // Component's own interfaces
+//        Map<String, InterfaceDefinition> interfaces = component.getInterfaces();
+//        if(MapUtils.isNotEmpty(interfaces)){
+//            for(Map.Entry<String, InterfaceDefinition> interfaceEntry : interfaces.entrySet()) {
+//                if (isPropertyExistInOperationInterface(propertyDefinitionEntry, interfaceEntry.getValue())) {
+//                    return true;
+//                }
+//            }
+//        }
+//
+//        // Component's child's component interfaces
+//        if(isPropertyUsedInCIInterfaces(component.getComponentInstancesInterfaces(), propertyDefinitionEntry)){
+//            return true;
+//        }
+//
+//        // Component's parent's component interfaces
+//        Either<List<Component>, StorageOperationStatus> componentList = toscaOperationFacade.getParentComponents(component.getUniqueId());
+//        if(componentList.isLeft()){
+//            for (Component parentComponent : componentList.left().value()) {
+//                if(isPropertyUsedInCIInterfaces(parentComponent.getComponentInstancesInterfaces(), propertyDefinitionEntry)){
+//                    return true;
+//                }
+//            }
+//        }
+//
+//        return false;
+    }
+
+
 }