Single node copy paste keyboard shorcut on canvas 53/65153/23
authorSindhuri.A <arcot.sindhuri@huawei.com>
Fri, 7 Sep 2018 08:23:56 +0000 (13:53 +0530)
committerMichael Lando <michael.lando@intl.att.com>
Tue, 16 Oct 2018 16:44:31 +0000 (16:44 +0000)
Keyboard Shortcut copy paste for single node on Composition page canvas for services

Issue-ID: SDC-1736

Change-Id: I669a728d3641a59ba7a4d8cc18fdae1000a0377f
Signed-off-by: Sindhuri.A <arcot.sindhuri@huawei.com>
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-be/src/main/resources/config/error-configuration.yaml
catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogicTest.java
catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ComponentInstanceServletTest.java
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/NodeTemplateOperation.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/ToscaOperationFacade.java

index 35493f7..04d543c 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.
@@ -36,43 +36,45 @@ import org.openecomp.sdc.be.dao.api.ActionStatus;
 import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
 import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
-import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.ForwardingPathDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.GetInputValueDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition;
-import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
+import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
 import org.openecomp.sdc.be.impl.ForwardingPathUtils;
 import org.openecomp.sdc.be.info.CreateAndAssotiateInfo;
-import org.openecomp.sdc.be.model.ArtifactDefinition;
-import org.openecomp.sdc.be.model.CapabilityDefinition;
 import org.openecomp.sdc.be.model.Component;
-import org.openecomp.sdc.be.model.ComponentInstance;
-import org.openecomp.sdc.be.model.ComponentInstanceInput;
-import org.openecomp.sdc.be.model.ComponentInstanceProperty;
 import org.openecomp.sdc.be.model.ComponentParametersView;
+import org.openecomp.sdc.be.model.CapabilityDefinition;
+import org.openecomp.sdc.be.model.RequirementDefinition;
+import org.openecomp.sdc.be.model.Resource;
+import org.openecomp.sdc.be.model.Service;
+import org.openecomp.sdc.be.model.User;
+import org.openecomp.sdc.be.model.ComponentInstancePropInput;
+import org.openecomp.sdc.be.model.LifecycleStateEnum;
+import org.openecomp.sdc.be.model.ArtifactDefinition;
 import org.openecomp.sdc.be.model.DataTypeDefinition;
+import org.openecomp.sdc.be.model.PropertyDefinition;
 import org.openecomp.sdc.be.model.GroupDefinition;
 import org.openecomp.sdc.be.model.InputDefinition;
-import org.openecomp.sdc.be.model.LifecycleStateEnum;
-import org.openecomp.sdc.be.model.PropertyDefinition;
-import org.openecomp.sdc.be.model.PropertyDefinition.PropertyNames;
 import org.openecomp.sdc.be.model.RelationshipInfo;
 import org.openecomp.sdc.be.model.RequirementCapabilityRelDef;
-import org.openecomp.sdc.be.model.RequirementDefinition;
-import org.openecomp.sdc.be.model.Resource;
-import org.openecomp.sdc.be.model.Service;
-import org.openecomp.sdc.be.model.User;
+import org.openecomp.sdc.be.model.ComponentInstance;
+import org.openecomp.sdc.be.model.ComponentInstanceInput;
+import org.openecomp.sdc.be.model.ComponentInstanceProperty;
+import org.openecomp.sdc.be.model.PropertyDefinition.PropertyNames;
 import org.openecomp.sdc.be.model.jsontitan.operations.ForwardingPathOperation;
 import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade;
 import org.openecomp.sdc.be.model.jsontitan.utils.ModelConverter;
 import org.openecomp.sdc.be.model.operations.api.IComponentInstanceOperation;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
+import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
 import org.openecomp.sdc.be.resources.data.ComponentInstanceData;
@@ -132,11 +134,11 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
     @Autowired
     private ForwardingPathOperation forwardingPathOperation;
 
-
     public ComponentInstanceBusinessLogic() {
     }
 
-    public Either<ComponentInstance, ResponseFormat> createComponentInstance(String containerComponentParam, String containerComponentId, String userId, ComponentInstance resourceInstance) {
+    public Either<ComponentInstance, ResponseFormat> createComponentInstance(
+            String containerComponentParam, String containerComponentId, String userId, ComponentInstance resourceInstance) {
         return createComponentInstance(containerComponentParam, containerComponentId, userId, resourceInstance, false, true);
     }
 
@@ -171,7 +173,6 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
             });
         }
         return resList;
-
     }
 
     public List<ComponentInstanceInput> getComponentInstanceInputsByInputId(org.openecomp.sdc.be.model.Component component, String inputId){
@@ -205,10 +206,10 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
             });
         }
         return resList;
-
     }
 
-    public Either<ComponentInstance, ResponseFormat> createComponentInstance(String containerComponentParam, String containerComponentId, String userId, ComponentInstance resourceInstance, boolean inTransaction, boolean needLock) {
+    public Either<ComponentInstance, ResponseFormat> createComponentInstance(
+            String containerComponentParam, String containerComponentId, String userId, ComponentInstance resourceInstance, boolean inTransaction, boolean needLock) {
 
         Component origComponent = null;
         Either<ComponentInstance, ResponseFormat> resultOp = null;
@@ -462,15 +463,15 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         return resultOp;
     }
 
-/**
- * addResourceInstanceArtifacts - add artifacts (HEAT_ENV) to resource instance The instance artifacts are generated from the resource's artifacts
- * @param containerComponent
- * @param componentInstance
- * @param originComponent
- * @param user
- * @param existingEnvVersions
- * @return
- */
+    /**
    * addResourceInstanceArtifacts - add artifacts (HEAT_ENV) to resource instance The instance artifacts are generated from the resource's artifacts
    * @param containerComponent
    * @param componentInstance
    * @param originComponent
    * @param user
    * @param existingEnvVersions
    * @return
    */
     protected Either<ActionStatus, ResponseFormat> addComponentInstanceArtifacts(org.openecomp.sdc.be.model.Component containerComponent, ComponentInstance componentInstance, org.openecomp.sdc.be.model.Component originComponent, User user,    Map<String, String> existingEnvVersions) {
 
         log.debug("add artifacts to resource instance");
@@ -584,7 +585,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
     }
 
     public Either<ComponentInstance, ResponseFormat> updateComponentInstanceMetadata(String containerComponentParam, String containerComponentId, String componentInstanceId, String userId, ComponentInstance componentInstance, boolean inTransaction,
-            boolean needLock, boolean createNewTransaction) {
+                                                                                     boolean needLock, boolean createNewTransaction) {
 
         validateUserExists(userId, "update Component Instance", inTransaction);
 
@@ -682,7 +683,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                 boolean validateParent = validateParent(containerComponent, componentInstance.getUniqueId());
                 if (!validateParent) {
                     resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND_ON_CONTAINER, componentInstance.getName(), instanceType.getValue().toLowerCase(), containerComponentType.getValue().toLowerCase(),
-                        containerComponentId));
+                            containerComponentId));
                     return resultOp;
                 }
             }
@@ -761,7 +762,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
     }
 
     private Either<ComponentInstance, ResponseFormat> updateComponentInstanceMetadata(Component containerComponent, ComponentTypeEnum containerComponentType, org.openecomp.sdc.be.model.Component origComponent, String componentInstanceId,
-            ComponentInstance componentInstance) {
+                                                                                      ComponentInstance componentInstance) {
 
         Either<ComponentInstance, ResponseFormat> resultOp = null;
         Optional<ComponentInstance> componentInstanceOptional = null;
@@ -881,7 +882,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                 return resultOp;
             }
             Either<ComponentInstance, ResponseFormat> deleteEither = deleteForwardingPathsRelatedTobeDeletedComponentInstance(containerComponentId,
-                containerComponentType, resultOp);
+                    containerComponentType, resultOp);
             if (deleteEither.isRight()){
                 return deleteEither;
             }
@@ -893,7 +894,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
     }
 
     public Either<ComponentInstance, ResponseFormat> deleteForwardingPathsRelatedTobeDeletedComponentInstance(String containerComponentId, ComponentTypeEnum containerComponentType,
-            Either<ComponentInstance, ResponseFormat> resultOp) {
+                                                                                                              Either<ComponentInstance, ResponseFormat> resultOp) {
         if(containerComponentType.equals(ComponentTypeEnum.SERVICE) && resultOp.isLeft() ){
             final ComponentInstance componentInstance = resultOp.left().value();
             List<String> pathIDsToBeDeleted = getForwardingPathsRelatedToComponentInstance(containerComponentId, componentInstance.getName());
@@ -917,7 +918,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
             return Either.right(componentsUtils.getResponseFormat(storageStatus.right().value()));
         }
         Either<Set<String>, StorageOperationStatus> result = forwardingPathOperation.deleteForwardingPath(storageStatus.left().value(),
-            Sets.newHashSet(pathIdsToDelete));
+                Sets.newHashSet(pathIdsToDelete));
 
         if(result.isRight()) {
             return Either.right(componentsUtils.getResponseFormat(result.right().value()));
@@ -944,7 +945,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         return pathDataDefinition.getPathElements().getListToscaDataDefinition()
                 .stream().anyMatch(elementDataDefinition -> elementDataDefinition.getFromNode().equalsIgnoreCase(componentInstanceId) ||
                         elementDataDefinition.getToNode()
-                 .equalsIgnoreCase(componentInstanceId));
+                                .equalsIgnoreCase(componentInstanceId));
     }
 
 
@@ -1021,7 +1022,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
     }
 
     public Either<RequirementCapabilityRelDef, ResponseFormat> associateRIToRI(String componentId, String userId, RequirementCapabilityRelDef requirementDef, ComponentTypeEnum componentTypeEnum, boolean inTransaction, boolean needLock,
-        boolean createNewTransaction) {
+                                                                               boolean createNewTransaction) {
 
         validateUserExists(userId, "associate Ri To RI", inTransaction);
 
@@ -1240,8 +1241,8 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
 
     private boolean isBelongingRequirement(RelationshipInfo relationshipInfo, RequirementDataDefinition req) {
         return  req.getName().equals(relationshipInfo.getRequirement()) &&
-            req.getUniqueId().equals(relationshipInfo.getRequirementUid()) &&
-            req.getOwnerId().equals(relationshipInfo.getRequirementOwnerId());
+                req.getUniqueId().equals(relationshipInfo.getRequirementUid()) &&
+                req.getOwnerId().equals(relationshipInfo.getRequirementOwnerId());
     }
 
     private Either<RequirementCapabilityRelDef, ResponseFormat> setRelatedCapability(RequirementCapabilityRelDef foundRelation, Component containerComponent) {
@@ -1688,7 +1689,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
     }
 
     public Either<ComponentInstanceProperty, ResponseFormat> createOrUpdateGroupInstancePropertyValue(ComponentTypeEnum componentTypeEnum, String componentId, String resourceInstanceId, String groupInstanceId, ComponentInstanceProperty property,
-        String userId) {
+                                                                                                      String userId) {
 
         Either<ComponentInstanceProperty, ResponseFormat> resultOp = null;
 
@@ -1955,33 +1956,33 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         return eitherResponse;
     }
 
-      public Either<Set<String>, ResponseFormat> forwardingPathOnVersionChange(String containerComponentParam,
-                                                                                String containerComponentId,
-                                                                                String componentInstanceId,
-                                                                                ComponentInstance newComponentInstance) {
+    public Either<Set<String>, ResponseFormat> forwardingPathOnVersionChange(String containerComponentParam,
+                                                                             String containerComponentId,
+                                                                             String componentInstanceId,
+                                                                             ComponentInstance newComponentInstance) {
         Either<Set<String>, ResponseFormat> resultOp;
         Either<ComponentTypeEnum, ResponseFormat> validateComponentType = validateComponentType(containerComponentParam);
         if (validateComponentType.isRight()) {
-          return Either.right(validateComponentType.right().value());
+            return Either.right(validateComponentType.right().value());
         }
         final ComponentTypeEnum containerComponentType = validateComponentType.left().value();
         ComponentParametersView componentParametersView = getComponentParametersViewForForwardingPath();
 
         //Fetch Component
         Either<org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponentExists =
-            validateComponentExists(containerComponentId, containerComponentType, componentParametersView);
+                validateComponentExists(containerComponentId, containerComponentType, componentParametersView);
         if (validateComponentExists.isRight()) {
-          return Either.right(validateComponentExists.right().value());
+            return Either.right(validateComponentExists.right().value());
         }
         Component containerComponent = validateComponentExists.left().value();
 
         //Fetch current component instance
         Either<ComponentInstance, StorageOperationStatus> eitherResourceInstance =
-            getResourceInstanceById(containerComponent, componentInstanceId);
+                getResourceInstanceById(containerComponent, componentInstanceId);
         if (eitherResourceInstance.isRight()) {
-          resultOp = Either.right(componentsUtils.getResponseFormat(
-              ActionStatus.RESOURCE_INSTANCE_NOT_FOUND_ON_SERVICE, componentInstanceId, containerComponentId));
-          return resultOp;
+            resultOp = Either.right(componentsUtils.getResponseFormat(
+                    ActionStatus.RESOURCE_INSTANCE_NOT_FOUND_ON_SERVICE, componentInstanceId, containerComponentId));
+            return resultOp;
         }
         ComponentInstance currentResourceInstance = eitherResourceInstance.left().value();
 
@@ -1989,29 +1990,29 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         String resourceId = newComponentInstance.getComponentUid();
         Either<Boolean, StorageOperationStatus> componentExistsRes = toscaOperationFacade.validateComponentExists(resourceId);
         if (componentExistsRes.isRight()) {
-          log.debug("Failed to find resource ", resourceId);
-          resultOp = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse
-              (componentExistsRes.right().value()), resourceId));
-          return resultOp;
+            log.debug("Failed to find resource ", resourceId);
+            resultOp = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse
+                    (componentExistsRes.right().value()), resourceId));
+            return resultOp;
         } else if (!componentExistsRes.left().value()) {
-          log.debug("The resource {} not found ", resourceId);
-          resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, resourceId));
-          return resultOp;
+            log.debug("The resource {} not found ", resourceId);
+            resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, resourceId));
+            return resultOp;
         }
 
         //Fetch component using new component instance uid
         Either<Component, ResponseFormat> eitherResourceName = getOriginComponentFromComponentInstance(newComponentInstance);
         if (eitherResourceName.isRight()) {
-          resultOp = Either.right(eitherResourceName.right().value());
-          return resultOp;
+            resultOp = Either.right(eitherResourceName.right().value());
+            return resultOp;
         }
         Component updatedContainerComponent=eitherResourceName.left().value();
         Set<String> toDeleteForwardingPaths = getForwardingPaths(containerComponent,
-            currentResourceInstance, updatedContainerComponent);
+                currentResourceInstance, updatedContainerComponent);
         resultOp=Either.left(toDeleteForwardingPaths);
 
         return resultOp;
-      }
+    }
 
     private Set<String> getForwardingPaths(Component containerComponent, ComponentInstance currentResourceInstance,
                                            Component updatedContainerComponent) {
@@ -2022,7 +2023,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         ForwardingPathUtils forwardingPathUtils = new ForwardingPathUtils();
 
         return forwardingPathUtils.
-            getForwardingPathsToBeDeletedOnVersionChange(service,dataForMergeHolder,updatedContainerComponent);
+                getForwardingPathsToBeDeletedOnVersionChange(service,dataForMergeHolder,updatedContainerComponent);
     }
 
     private ComponentParametersView getComponentParametersViewForForwardingPath() {
@@ -2499,7 +2500,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         Component containerComponent = getResourceResult.left().value();
 
         if (!ComponentValidationUtils.canWorkOnComponent(containerComponent, userId)) {
-            log.info("Restricted operation for user: {} on component {}", userId, containerComponentId);
+            log.info("Restricted operation for user: {sourcePropList} on component {}", userId, containerComponentId);
             return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
         }
         Either<ComponentInstance, StorageOperationStatus> resourceInstanceStatus = getResourceInstanceById(containerComponent, componentInstanceUniqueId);
@@ -2525,8 +2526,8 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
             for (ComponentInstanceProperty property : properties) {
                 Either<String, ResponseFormat> newPropertyValueEither = updatePropertyObjectValue(property, false);
                 newPropertyValueEither.bimap(updatedValue ->
-                        updateCapabilityPropertyOnContainerComponent(property,updatedValue, containerComponent, foundResourceInstance, capabilityType, capabilityName, ownerId),
-                    responseFormat -> Either.right(responseFormat));
+                                updateCapabilityPropertyOnContainerComponent(property,updatedValue, containerComponent, foundResourceInstance, capabilityType, capabilityName, ownerId),
+                        responseFormat -> Either.right(responseFormat));
             }
             Either<Component, StorageOperationStatus> updateContainerRes = toscaOperationFacade.updateComponentInstanceMetadataOfTopologyTemplate(containerComponent);
 
@@ -2550,7 +2551,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
     }
 
     public Either<List<ComponentInstanceProperty>, ResponseFormat> updateInstanceCapabilityProperties(ComponentTypeEnum componentTypeEnum, String containerComponentId, String componentInstanceUniqueId, String capabilityType, String capabilityName,
-        List<ComponentInstanceProperty> properties, String userId) {
+                                                                                                      List<ComponentInstanceProperty> properties, String userId) {
         Either<List<ComponentInstanceProperty>, ResponseFormat> resultOp = null;
 
         validateUserExists(userId, "update instance capability property", false);
@@ -2610,4 +2611,382 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
             graphLockOperation.unlockComponent(containerComponentId, componentTypeEnum.getNodeType());
         }
     }
+
+    public Either<Map<String, ComponentInstance>, ResponseFormat> copyComponentInstance(ComponentInstance inputComponentInstance,
+                                                                                        String containerComponentId,
+                                                                                        String componentInstanceId,
+                                                                                        String userId) {
+
+        Map<String, ComponentInstance> resultMap = new HashMap<>();
+        Either<Component, StorageOperationStatus> getOrigComponent = toscaOperationFacade.getToscaElement(containerComponentId);
+        if (getOrigComponent.isRight()) {
+            log.error("Failed to get the original component information");
+            return Either.right(componentsUtils.getResponseFormat(
+                    ActionStatus.USER_DEFINED, "Failed to copy the component instance to the canvas"));
+        }
+
+        Component origComponent = getOrigComponent.left().value();
+
+        Either<Boolean, ResponseFormat> lockComponent = lockComponent(origComponent, "copyComponentInstance");
+        if (lockComponent.isRight()) {
+            log.error("destComponentInstance's data is {}", origComponent.toString());
+            return Either.right(lockComponent.right().value());
+        }
+
+
+        Either<ComponentInstance, ResponseFormat> actionResponse = null;
+        try {
+            actionResponse = createComponentInstance(
+                    "services", containerComponentId, userId, inputComponentInstance, true, false);
+
+
+        }
+        finally {
+
+            // on failure of the create instance unlock the resource and rollback the transaction.
+            if (null== actionResponse || actionResponse.isRight()) {
+                titanDao.rollback();
+                log.error("Failed to copy the component instance to the canvas");
+
+                unlockComponent(actionResponse, origComponent);
+
+                return Either.right(componentsUtils.getResponseFormat(
+                        ActionStatus.USER_DEFINED, "Failed to copy the component instance to the canvas"));
+            }
+
+        }
+
+        Either<String, ResponseFormat> resultOp = null;
+
+        try {
+            ComponentInstance destComponentInstance = actionResponse.left().value();
+            log.debug("destComponentInstance's data is {}", destComponentInstance.toString());
+
+
+            resultOp = deepCopyComponentInstance(
+                    origComponent, containerComponentId, componentInstanceId, destComponentInstance, userId);
+
+            resultMap.put("componentInstance", destComponentInstance);
+        }
+        finally{
+            // unlock resource
+            unlockComponent(resultOp, origComponent);
+
+            if (resultOp == null || resultOp.isRight()) {
+                titanDao.rollback();
+                log.error("Failed to deep copy component instance");
+                return Either.right(componentsUtils.getResponseFormat(
+                        ActionStatus.USER_DEFINED, "Failed to deep copy the component instance to the canvas"));
+            } else {
+                titanDao.commit();
+                log.debug("Success trasaction commit");
+            }
+        }
+
+        return Either.left(resultMap);
+    }
+
+    private Either<String, ResponseFormat> deepCopyComponentInstance(
+            Component sourceComponent, String containerComponentId, String sourceComponentInstanceId,
+            ComponentInstance destComponentInstance, String userId) {
+
+        Either<Component, StorageOperationStatus> getDestComponent = toscaOperationFacade.getToscaElement(containerComponentId);
+        if (getDestComponent.isRight()) {
+            log.error("Failed to get the dest component information");
+            return Either.right(componentsUtils.getResponseFormat(
+                    ActionStatus.USER_DEFINED, "Failed to copy the component instance to the canvas"));
+        }
+
+        Component destComponent = getDestComponent.left().value();
+
+        Either<String, ResponseFormat> copyComponentInstanceWithPropertiesAndInputs = copyComponentInstanceWithPropertiesAndInputs(
+                sourceComponent, destComponent, sourceComponentInstanceId, destComponentInstance, userId);
+        if (copyComponentInstanceWithPropertiesAndInputs.isRight()) {
+            log.error("Failed to copy component instance with properties and inputs as part of deep copy");
+            return Either.right(componentsUtils.getResponseFormat(
+                    ActionStatus.USER_DEFINED, "Failed to copy the component instance with properties and inputs as part of deep copy"));
+        }
+
+        Either<String, ResponseFormat> copyComponentInstanceWithAttributes = copyComponentInstanceWithAttributes(
+                sourceComponent, destComponent, sourceComponentInstanceId, destComponentInstance, userId);
+        if (copyComponentInstanceWithAttributes.isRight()) {
+            log.error("Failed to copy component instance with attributes as part of deep copy");
+            return Either.right(componentsUtils.getResponseFormat(
+                    ActionStatus.USER_DEFINED, "Failed to copy the component instance with attributes as part of deep copy"));
+        }
+        return Either.left("Copy component Instance OK");
+    }
+
+    private Either<String, ResponseFormat> copyComponentInstanceWithPropertiesAndInputs(
+            Component sourceComponent, Component destComponent, String sourceComponentInstanceId,
+            ComponentInstance destComponentInstance, String userId) {
+        log.debug("start to copy ComponentInstance with properties and inputs");
+
+        List<ComponentInstanceProperty> sourcePropList = null;
+        if (sourceComponent.getComponentInstancesProperties() != null
+                && sourceComponent.getComponentInstancesProperties().get(sourceComponentInstanceId) != null) {
+            sourcePropList = sourceComponent.getComponentInstancesProperties().get(sourceComponentInstanceId);
+            log.debug("sourcePropList");
+        }
+
+        List<ComponentInstanceProperty> destPropList = null;
+        String destComponentInstanceId = destComponentInstance.getUniqueId();
+        log.debug("destComponentInstanceId: {}", destComponentInstance.getUniqueId());
+        if (destComponent.getComponentInstancesProperties() != null
+                && destComponent.getComponentInstancesProperties().get(destComponentInstanceId) != null) {
+            destPropList = destComponent.getComponentInstancesProperties().get(destComponentInstanceId);
+            log.debug("destPropList {}");
+        }
+
+        List<ComponentInstancePropInput> componentInstancePropInputList = new ArrayList<>();
+
+        if (null != destPropList && null != sourcePropList) {
+            log.debug("start to set property and attribute");
+            for (ComponentInstanceProperty destProp : destPropList) {
+                String destPropertyName = destProp.getName();
+                for (ComponentInstanceProperty sourceProp : sourcePropList) {
+                    if (!destPropertyName.equals(sourceProp.getName())) {
+                        continue;
+                    }
+                    log.debug("now set property");
+                    if (sourceProp.getGetInputValues() == null && !StringUtils.isEmpty(sourceProp.getValue())
+                            && (destProp.getValue() == null || !destProp.getValue().equals(sourceProp.getValue()))) {
+                        log.debug("Now starting to copy the property {} in value {}", destPropertyName, sourceProp.getValue());
+
+                        destProp.setValue(sourceProp.getValue());
+                        Either<String, ResponseFormat> updatePropertyValueEither = updateComponentInstanceProperty(
+                                destComponent.getUniqueId(), destComponentInstanceId, destProp);
+                        if (updatePropertyValueEither.isRight()) {
+                            log.error("Failed to copy the property {}", destPropertyName);
+                            return Either.right(componentsUtils.getResponseFormat(
+                                    ActionStatus.INVALID_CONTENT_PARAM, "Failed to paste component instance to the canvas, property copy"));
+                        }
+                        break;
+                    }
+
+                    log.debug("Now start to update inputs");
+
+                    if (sourceProp.getGetInputValues() != null) {
+                        if (sourceProp.getGetInputValues().size() < 1) {
+                            log.debug("property is return from input, set by man");
+                            break;
+                        }
+                        log.debug("Now starting to copy the {} property", destPropertyName);
+
+                        Either<String, ResponseFormat> getSourceInputDefaultValue = getInputListDefaultValue(
+                                sourceComponent, sourceProp.getGetInputValues().get(0).getInputId());
+                        if (getSourceInputDefaultValue.isRight()) {
+                            return Either.right(getSourceInputDefaultValue.right().value());
+                        }
+                        componentInstancePropInputList.add(new ComponentInstancePropInput(destProp));
+                    }
+                }
+            }
+        }
+        return Either.left("Copy component Instance OK");
+    }
+
+    private Either<String, ResponseFormat> copyComponentInstanceWithAttributes(Component sourceComponent,
+                                                                               Component destComponent,
+                                                                               String sourceComponentInstanceId,
+                                                                               ComponentInstance destComponentInstance,
+                                                                               String userId) {
+        String destComponentInstanceId = destComponentInstance.getUniqueId();
+
+        log.info("start to copy component instance with attributes");
+
+        List<ComponentInstanceProperty> sourceAttributeList = null;
+        if (sourceComponent.getComponentInstancesAttributes() != null
+                && sourceComponent.getComponentInstancesAttributes().get(sourceComponentInstanceId) != null) {
+            sourceAttributeList = sourceComponent.getComponentInstancesAttributes().get(sourceComponentInstanceId);
+            log.info("sourceAttributes {}");
+        }
+
+        List<ComponentInstanceProperty> destAttributeList = null;
+        if (destComponent.getComponentInstancesAttributes() != null
+                && destComponent.getComponentInstancesAttributes().get(destComponentInstanceId) != null) {
+            destAttributeList = destComponent.getComponentInstancesAttributes().get(destComponentInstanceId);
+            log.info("destAttributeList {}");
+        }
+        if (null != sourceAttributeList && null != destAttributeList) {
+            log.info("set attribute");
+
+            for (ComponentInstanceProperty sourceAttribute : sourceAttributeList) {
+                String sourceAttributeName = sourceAttribute.getName();
+                for (ComponentInstanceProperty destAttribute : destAttributeList) {
+                    if (sourceAttributeName.equals(destAttribute.getName())) {
+                        if (sourceAttribute.getValue() != null && !sourceAttribute.getValue().isEmpty()) {
+                            log.debug("Start to copy the attribute exists {}", sourceAttributeName);
+
+                            sourceAttribute.setUniqueId(
+                                    UniqueIdBuilder.buildResourceInstanceUniuqeId(
+                                    "attribute" , destComponentInstanceId.split("\\.")[1] , sourceAttributeName));
+
+                            Either<ComponentInstanceProperty, ResponseFormat> updateAttributeValueEither =
+                                    createOrUpdateAttributeValueForCopyPaste(ComponentTypeEnum.SERVICE,
+                                            destComponent.getUniqueId(), destComponentInstanceId, sourceAttribute,
+                                            userId);
+                            if (updateAttributeValueEither.isRight()) {
+                                log.error("Failed to copy the attribute");
+                                return Either.right(componentsUtils
+                                        .getResponseFormat(ActionStatus.INVALID_CONTENT_PARAM,
+                                                "Failed to paste component instance to the canvas, attribute copy"));
+                            }
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        return Either.left("Copy component Instance OK");
+    }
+
+    private Either<ComponentInstanceProperty, ResponseFormat> createOrUpdateAttributeValueForCopyPaste(ComponentTypeEnum componentTypeEnum,
+                                                                                                       String componentId,
+                                                                                                       String resourceInstanceId,
+                                                                                                       ComponentInstanceProperty attribute,
+                                                                                                       String userId) {
+
+        Either<ComponentInstanceProperty, ResponseFormat> resultOp = null;
+
+        validateUserExists(userId, "Create or Update attribute value", false);
+
+        if (componentTypeEnum == null) {
+            BeEcompErrorManager.getInstance().logInvalidInputError(
+                    "createOrUpdateAttributeValue", "invalid component type", ErrorSeverity.INFO);
+            resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.NOT_ALLOWED));
+            return resultOp;
+        }
+
+        Either<Component, StorageOperationStatus> getResourceResult = toscaOperationFacade.getToscaElement(componentId, JsonParseFlagEnum.ParseAll);
+
+        if (getResourceResult.isRight()) {
+            log.info("Failed to retrieve component id {}", componentId);
+            resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
+            return resultOp;
+        }
+
+        Component containerComponent = getResourceResult.left().value();
+
+        Either<ComponentInstance, StorageOperationStatus> resourceInstanceStatus = getResourceInstanceById(containerComponent, resourceInstanceId);
+
+        if (resourceInstanceStatus.isRight()) {
+            resultOp = Either.right(componentsUtils.getResponseFormat(
+                    ActionStatus.RESOURCE_INSTANCE_NOT_FOUND_ON_SERVICE, resourceInstanceId, componentId));
+            return resultOp;
+        }
+
+        ComponentInstance foundResourceInstance = resourceInstanceStatus.left().value();
+
+
+        String propertyType = attribute.getType();
+        ToscaPropertyType type = ToscaPropertyType.isValidType(propertyType);
+        log.info("The type of attribute id{},is {} ", attribute.getUniqueId(), propertyType);
+
+        if (type == ToscaPropertyType.LIST || type == ToscaPropertyType.MAP) {
+            SchemaDefinition def = attribute.getSchema();
+            if (def == null) {
+                log.info("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.info("Attribute in Schema Definition inside attribute of type {} doesn't exist", type);
+                return Either.right(componentsUtils.getResponseFormat(
+                        componentsUtils.convertFromStorageResponse(StorageOperationStatus.INVALID_VALUE)));
+            }
+        }
+
+        List<ComponentInstanceProperty> instanceAttributes = containerComponent.
+                getComponentInstancesAttributes().get(resourceInstanceId);
+        Optional<ComponentInstanceProperty> instanceAttribute =
+                instanceAttributes.stream().filter(p -> p.getUniqueId().equals(attribute.getUniqueId())).findAny();
+        StorageOperationStatus status;
+
+        if (instanceAttribute.isPresent()) {
+            log.info("updateComponentInstanceAttribute");
+            status = toscaOperationFacade.updateComponentInstanceAttribute(containerComponent, foundResourceInstance.getUniqueId(), attribute);
+        } else {
+            log.info("addComponentInstanceAttribute");
+            status = toscaOperationFacade.addComponentInstanceAttribute(containerComponent, foundResourceInstance.getUniqueId(), attribute);
+        }
+        if (status != StorageOperationStatus.OK) {
+            ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(status);
+            resultOp = Either.right(componentsUtils.getResponseFormatForResourceInstanceProperty(actionStatus, ""));
+            return resultOp;
+        }
+        List<String> path = new ArrayList<>();
+        path.add(foundResourceInstance.getUniqueId());
+        attribute.setPath(path);
+
+        foundResourceInstance.setCustomizationUUID(UUID.randomUUID().toString());
+        Either<Component, StorageOperationStatus> updateContainerRes = toscaOperationFacade.
+                updateComponentInstanceMetadataOfTopologyTemplate(containerComponent);
+
+        if (updateContainerRes.isRight()) {
+            ActionStatus actionStatus = componentsUtils.
+                    convertFromStorageResponseForResourceInstanceProperty(updateContainerRes.right().value());
+            resultOp = Either.right(componentsUtils.
+                    getResponseFormatForResourceInstanceProperty(actionStatus, ""));
+            return resultOp;
+        }
+        resultOp = Either.left(attribute);
+        return resultOp;
+
+
+
+    }
+
+    private Either<String, ResponseFormat> updateComponentInstanceProperty(String containerComponentId,
+                                                                           String componentInstanceId,
+                                                                           ComponentInstanceProperty property) {
+        Either<String, ResponseFormat> resultOp;
+        Either<Component, StorageOperationStatus> getComponent = toscaOperationFacade.getToscaElement(containerComponentId);
+
+        if (getComponent.isRight()) {
+            log.error("Failed to get the component information");
+            return Either.right(componentsUtils.getResponseFormatForResourceInstanceProperty(
+                    ActionStatus.INVALID_CONTENT_PARAM, "Failed to get the component information"));
+        }
+
+        Component containerComponent = getComponent.left().value();
+
+        StorageOperationStatus status = toscaOperationFacade.updateComponentInstanceProperty(
+                containerComponent, componentInstanceId, property);
+        if (status != StorageOperationStatus.OK) {
+            ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(status);
+            resultOp = Either.right(componentsUtils.getResponseFormatForResourceInstanceProperty(actionStatus, ""));
+            return resultOp;
+        }
+
+        Either<Component, StorageOperationStatus> updateContainerRes = toscaOperationFacade.
+                updateComponentInstanceMetadataOfTopologyTemplate(containerComponent);
+
+        if (updateContainerRes.isRight()) {
+            ActionStatus actionStatus = componentsUtils.
+                    convertFromStorageResponseForResourceInstanceProperty(updateContainerRes.right().value());
+            resultOp = Either.right(componentsUtils.getResponseFormatForResourceInstanceProperty(actionStatus, ""));
+            return resultOp;
+        }
+
+        return Either.left("Update OK");
+    }
+
+    private Either<String, ResponseFormat> getInputListDefaultValue(Component component, String inputId) {
+        List<InputDefinition> inputList = component.getInputs();
+        for (InputDefinition input : inputList) {
+            if (input.getUniqueId().equals(inputId)) {
+                if (input.getDefaultValue() == null) {
+                    log.debug("The input's default value is null");
+                    return Either.left(null);
+                }
+                return Either.left(input.getDefaultValue());
+            }
+        }
+        log.error("The input's default value with id {} is not found", inputId);
+        return Either.right(componentsUtils.getResponseFormat(
+                ActionStatus.USER_DEFINED, "Failed to paste component instance to the canvas"));
+    }
 }
index dec12d7..3195727 100644 (file)
@@ -58,6 +58,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
+import java.util.Map;
 
 /**
  * Root resource (exposed at "/" path) .json
@@ -1205,4 +1206,47 @@ public class ComponentInstanceServlet extends AbstractValidationsServlet {
 
     }
 
+    @POST
+    @Path("/services/{componentId}/copyComponentInstance/{componentInstanceId}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces((MediaType.APPLICATION_JSON))
+    @ApiOperation(value = "Copy Component Instance", httpMethod = "POST", notes = "Returns updated service information", response = Service.class)
+    @ApiResponses(value = {
+            @ApiResponse(code = 201, message = "Copy and Paste Success"),
+            @ApiResponse(code = 403, message = "Restricted Operation"),
+            @ApiResponse(code = 400, message = "Invalid Content / Missing content")})
+    public Response copyComponentInstance(
+            @ApiParam(value = "service unique id in pasted canvas") @PathParam("componentId") final String containerComponentId,
+            @ApiParam(value = "Data for copying", required = true) String data, @PathParam("componentInstanceId") final String componentInstanceId,
+            @Context final HttpServletRequest request) {
+        log.info("Start to copy component instance");
+        ServletContext context = request.getSession().getServletContext();
+        String userId = request.getHeader(Constants.USER_ID_HEADER);
+        final String CNTAINER_CMPT_TYPE = "services";
+
+        try {
+            ComponentInstance inputComponentInstance = RepresentationUtils.fromRepresentation(data, ComponentInstance.class);
+            inputComponentInstance.setInvariantName(null);
+            ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(CNTAINER_CMPT_TYPE);
+            ComponentInstanceBusinessLogic componentInstanceLogic = getComponentInstanceBL(context);
+            if (componentInstanceLogic == null) {
+                log.debug(UNSUPPORTED_COMPONENT_TYPE, componentTypeEnum);
+                return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, "services"));
+            }
+            Either<Map<String, ComponentInstance>, ResponseFormat> copyComponentInstance = componentInstanceLogic.copyComponentInstance(
+                    inputComponentInstance, containerComponentId, componentInstanceId, userId);
+
+            if (copyComponentInstance.isRight()) {
+                log.error("Failed to copy ComponentInstance {}", copyComponentInstance.right().value());
+                return buildErrorResponse(copyComponentInstance.right().value());
+            }
+
+            return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK),
+                    copyComponentInstance.left().value());
+        } catch (Exception e) {
+            log.error("Failed to convert json to Map { }, error: { }", data, e);
+            return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.USER_DEFINED,
+                    "Failed to get the copied component instance information"));
+        }
+    }
 }
index 6156090..aa000f1 100644 (file)
@@ -105,6 +105,12 @@ errors:
         message: "Error: Invalid userId '%1'.",
         messageId: "SVC4008"
     }
+#---------SVC4009-----------------------------
+    USER_DEFINED: {
+        code: 400,
+        message: "Error: User Defined '%1'.",
+        messageId: "SVC4009"
+    }
 #---------SVC4049------------------------------
 # %1 - service/resource
     COMPONENT_MISSING_CONTACT: {
index 1a64830..929bb97 100644 (file)
@@ -1,6 +1,5 @@
 package org.openecomp.sdc.be.components.impl;
 
-import static org.junit.Assert.assertSame;
 import static org.assertj.core.api.Assertions.assertThat;
 import fj.data.Either;
 
@@ -16,14 +15,18 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.junit.MockitoJUnitRunner;
 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
 import org.openecomp.sdc.be.components.validation.UserValidations;
 import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.dao.jsongraph.TitanDao;
 import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
+import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
 import org.openecomp.sdc.be.datatypes.elements.*;
 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
+import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
 import org.openecomp.sdc.be.impl.ComponentsUtils;
 import org.openecomp.sdc.be.impl.ServletUtils;
 import org.openecomp.sdc.be.info.CreateAndAssotiateInfo;
@@ -32,19 +35,22 @@ import org.openecomp.sdc.be.model.LifecycleStateEnum;
 import org.openecomp.sdc.be.model.jsontitan.operations.ForwardingPathOperation;
 import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
+import org.openecomp.sdc.be.model.operations.impl.GraphLockOperation;
 import org.openecomp.sdc.be.user.UserBusinessLogic;
+import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum;
 import org.openecomp.sdc.exception.ResponseFormat;
 
 import java.util.function.BiPredicate;
 
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anySet;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.when;
 
-import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.when;
 
@@ -86,6 +92,13 @@ public class ComponentInstanceBusinessLogicTest {
     private User user;
     @Mock
     private UserValidations userValidations;
+    @Mock
+    private TitanDao titanDao;
+    @Mock
+    private ArtifactsBusinessLogic artifactBusinessLogic;
+    @Mock
+    private GraphLockOperation graphLockOperation;
+    
     private Component service;
     private Component resource;
     private ComponentInstance toInstance;
@@ -158,8 +171,8 @@ public class ComponentInstanceBusinessLogicTest {
 
         Either<Set<String>, ResponseFormat> resultOp = componentInstanceBusinessLogic.forwardingPathOnVersionChange
             (containerComponentParam,containerComponentID,componentInstanceID,newComponentInstance);
-        Assert.assertEquals(1,resultOp.left().value().size());
-        Assert.assertEquals("FP-ID-1",resultOp.left().value().iterator().next());
+        assertEquals(1,resultOp.left().value().size());
+        assertEquals("FP-ID-1",resultOp.left().value().iterator().next());
 
     }
 
@@ -1067,4 +1080,205 @@ public class ComponentInstanceBusinessLogicTest {
         when(toscaOperationFacade.getToscaFullElement(containerComponentId)).thenReturn(Either.left(resource));
         result=testSubject.updateInstanceCapabilityProperties(componentTypeEnum, containerComponentId, componentInstanceUniqueId, capabilityType, capabilityName, properties, userId);
     }
+
+    @Test
+    public void testCopyComponentInstanceWrongUserId() {
+
+        Either<Map<String, ComponentInstance>, ResponseFormat> result;
+        ComponentInstance inputComponentInstance = createComponetInstanceFromComponent(resource);
+        String containerComponentId = service.getUniqueId();
+        String componentInstanceId = resource.getUniqueId();
+        String oldLastUpdatedUserId = service.getLastUpdaterUserId();
+        service.setLastUpdaterUserId("wrong user id");
+
+        Either<Component, StorageOperationStatus> leftServiceOp = Either.left(service);
+        when(toscaOperationFacade.getToscaElement(containerComponentId)).thenReturn(leftServiceOp);
+        when(toscaOperationFacade.getToscaElement(eq(containerComponentId), any(ComponentParametersView.class)))
+                .thenReturn(leftServiceOp);
+        when(titanDao.rollback()).thenReturn(TitanOperationStatus.OK);
+        when(graphLockOperation.unlockComponent(Mockito.anyString(), eq(NodeTypeEnum.Service)))
+                .thenReturn(StorageOperationStatus.OK);
+        when(graphLockOperation.lockComponent(Mockito.anyString(), eq(NodeTypeEnum.Service)))
+                .thenReturn(StorageOperationStatus.OK);
+
+        result = componentInstanceBusinessLogic
+                .copyComponentInstance(inputComponentInstance, containerComponentId, componentInstanceId, USER_ID);
+
+        service.setLastUpdaterUserId(oldLastUpdatedUserId);
+
+        assertThat(result.isRight());
+    }
+
+    @Test
+    public void testCopyComponentInstanceComponentWrongState() {
+        Either<Map<String, ComponentInstance>, ResponseFormat> result;
+        ComponentInstance inputComponentInstance = createComponetInstanceFromComponent(resource);
+        String containerComponentId = service.getUniqueId();
+        String componentInstanceId = resource.getUniqueId();
+        String oldServiceLastUpdatedUserId = service.getLastUpdaterUserId();
+        service.setLastUpdaterUserId(USER_ID);
+
+        Either<Component, StorageOperationStatus> leftServiceOp = Either.left(service);
+        when(toscaOperationFacade.getToscaElement(containerComponentId)).thenReturn(leftServiceOp);
+        when(toscaOperationFacade.getToscaElement(eq(containerComponentId), any(ComponentParametersView.class)))
+                .thenReturn(leftServiceOp);
+        when(titanDao.rollback()).thenReturn(TitanOperationStatus.OK);
+        when(graphLockOperation.unlockComponent(Mockito.anyString(), eq(NodeTypeEnum.Service)))
+                .thenReturn(StorageOperationStatus.OK);
+        when(graphLockOperation.lockComponent(Mockito.anyString(), eq(NodeTypeEnum.Service)))
+                .thenReturn(StorageOperationStatus.OK);
+        Either<Component, StorageOperationStatus> getComponentRes = Either.left(resource);
+        when(toscaOperationFacade.getToscaFullElement(inputComponentInstance.getComponentUid()))
+                .thenReturn(getComponentRes);
+
+        result = componentInstanceBusinessLogic
+                .copyComponentInstance(inputComponentInstance, containerComponentId, componentInstanceId, USER_ID);
+
+        service.setLastUpdaterUserId(oldServiceLastUpdatedUserId);
+
+        assertThat(result.isRight());
+    }
+
+    @Test
+    public void testCopyComponentInstance() {
+        Either<Map<String, ComponentInstance>, ResponseFormat> result;
+        ComponentInstance inputComponentInstance = createComponetInstanceFromComponent(resource);
+        String containerComponentId = service.getUniqueId();
+        String componentInstanceId = resource.getUniqueId();
+        String oldServiceLastUpdatedUserId = service.getLastUpdaterUserId();
+        service.setLastUpdaterUserId(USER_ID);
+        LifecycleStateEnum oldResourceLifeCycle = resource.getLifecycleState();
+        resource.setLifecycleState(LifecycleStateEnum.CERTIFIED);
+
+        Either<Component, StorageOperationStatus> leftServiceOp = Either.left(service);
+        when(toscaOperationFacade.getToscaElement(containerComponentId)).thenReturn(leftServiceOp);
+        when(toscaOperationFacade.getToscaElement(eq(containerComponentId), any(ComponentParametersView.class)))
+                .thenReturn(leftServiceOp);
+        when(graphLockOperation.unlockComponent(Mockito.anyString(), eq(NodeTypeEnum.Service)))
+                .thenReturn(StorageOperationStatus.OK);
+        when(graphLockOperation.lockComponent(Mockito.anyString(), eq(NodeTypeEnum.Service)))
+                .thenReturn(StorageOperationStatus.OK);
+        Either<Component, StorageOperationStatus> getComponentRes = Either.left(resource);
+        when(toscaOperationFacade.getToscaFullElement(inputComponentInstance.getComponentUid()))
+                .thenReturn(getComponentRes);
+        ImmutablePair<Component, String> pair = new ImmutablePair<>(resource, TO_INSTANCE_ID);
+        Either<ImmutablePair<Component, String>, StorageOperationStatus> result2 = Either.left(pair);
+        when(toscaOperationFacade
+                .addComponentInstanceToTopologyTemplate(eq(service), eq(resource), eq(inputComponentInstance), eq(false),
+                        isNull(User.class))).thenReturn(result2);
+        Either<Map<String, ArtifactDefinition>, StorageOperationStatus> getResourceDeploymentArtifacts = Either
+                .left(new HashMap<String, ArtifactDefinition>());
+        when(artifactBusinessLogic.getArtifacts(eq(inputComponentInstance.getComponentUid()), eq(NodeTypeEnum.Resource),
+                eq(ArtifactGroupTypeEnum.DEPLOYMENT), isNull(String.class))).thenReturn(getResourceDeploymentArtifacts);
+        StorageOperationStatus artStatus = StorageOperationStatus.OK;
+        when(toscaOperationFacade
+                .addInformationalArtifactsToInstance(eq(resource.getUniqueId()), eq(inputComponentInstance),
+                        isNull(Map.class))).thenReturn(artStatus);
+        
+        result = componentInstanceBusinessLogic
+                .copyComponentInstance(inputComponentInstance, containerComponentId, componentInstanceId, USER_ID);
+
+        service.setLastUpdaterUserId(oldServiceLastUpdatedUserId);
+        resource.setLifecycleState(oldResourceLifeCycle);
+
+        assertThat(result.isLeft());
+    }
+
+    @Test
+    public void testCreateOrUpdateAttributeValueForCopyPaste() {
+        ComponentInstance serviceComponentInstance = createComponetInstanceFromComponent(service);
+        ComponentInstanceProperty attribute = new ComponentInstanceProperty();
+        attribute.setType("string");
+        attribute.setUniqueId("testCreateOrUpdateAttributeValueForCopyPaste");
+        SchemaDefinition def = Mockito.mock(SchemaDefinition.class);
+        attribute.setSchema(def);
+        LifecycleStateEnum oldLifeCycleState = service.getLifecycleState();
+        String oldLastUpdatedUserId = service.getLastUpdaterUserId();
+        service.setLastUpdaterUserId(USER_ID);
+        service.setLifecycleState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
+
+        Map<String, List<ComponentInstanceProperty>> instAttrsMap = new HashMap<String, List<ComponentInstanceProperty>>();
+        List<ComponentInstanceProperty> instAttrsList = new ArrayList<ComponentInstanceProperty>();
+        ComponentInstanceProperty prop = new ComponentInstanceProperty();
+        prop.setUniqueId(attribute.getUniqueId());
+        instAttrsList.add(prop);
+        instAttrsMap.put(toInstance.getUniqueId(), instAttrsList);
+        service.setComponentInstancesAttributes(instAttrsMap);
+
+        Either<Component, StorageOperationStatus> serviceEitherLeft = Either.left(service);
+        when(toscaOperationFacade.getToscaElement(serviceComponentInstance.getUniqueId(), JsonParseFlagEnum.ParseAll)).thenReturn(serviceEitherLeft);
+        when(toscaOperationFacade.updateComponentInstanceAttribute(service, toInstance.getUniqueId(), attribute)).thenReturn(StorageOperationStatus.OK);
+        when(toscaOperationFacade.updateComponentInstanceMetadataOfTopologyTemplate(service)).thenReturn(serviceEitherLeft);
+
+        Either<ComponentInstanceProperty, ResponseFormat> result = Deencapsulation.invoke(componentInstanceBusinessLogic, "createOrUpdateAttributeValueForCopyPaste", ComponentTypeEnum.SERVICE,
+                serviceComponentInstance.getUniqueId(),
+                toInstance.getUniqueId(),
+                attribute,
+                USER_ID);
+
+        service.setLastUpdaterUserId(oldLastUpdatedUserId);
+        service.setLifecycleState(oldLifeCycleState);
+
+        assertTrue(result.isLeft());
+        ComponentInstanceProperty resultProp = result.left().value();
+        assertEquals(resultProp.getPath().size(), 1);
+        assertEquals(resultProp.getPath().get(0), toInstance.getUniqueId());
+    }
+
+    @Test
+    public void testUpdateComponentInstanceProperty() {
+
+        String containerComponentId = service.getUniqueId();
+        String componentInstanceId = "dummy_id";
+        ComponentInstanceProperty property = Mockito.mock(ComponentInstanceProperty.class);
+
+        Either<Component, StorageOperationStatus> getComponent = Either.left(service);
+        when(toscaOperationFacade.getToscaElement(containerComponentId)).thenReturn(getComponent);
+        StorageOperationStatus status = StorageOperationStatus.OK;
+        when(toscaOperationFacade.updateComponentInstanceProperty(service, componentInstanceId, property))
+                .thenReturn(status);
+        Either<Component, StorageOperationStatus> updateContainerRes = Either.left(service);
+        when(toscaOperationFacade.updateComponentInstanceMetadataOfTopologyTemplate(service))
+                .thenReturn(updateContainerRes);
+
+        Either<String, ResponseFormat> result = Deencapsulation
+                .invoke(componentInstanceBusinessLogic, "updateComponentInstanceProperty", containerComponentId,
+                        componentInstanceId, property);
+
+        assertTrue(result.isLeft());
+    }
+
+    @Test
+    public void testGetInputListDefaultValue() {
+        Component component = service;
+        String inputId = "dummy_id";
+        String defaultValue = "dummy_default_value";
+        List<InputDefinition> newInputs = new ArrayList<InputDefinition>();
+        InputDefinition in = new InputDefinition();
+        in.setUniqueId(inputId);
+        in.setDefaultValue(defaultValue);
+        newInputs.add(in);
+        List<InputDefinition> oldInputs = service.getInputs();
+        service.setInputs(newInputs);
+
+        Either<String, ResponseFormat> result = Deencapsulation
+                .invoke(componentInstanceBusinessLogic, "getInputListDefaultValue", component, inputId);
+
+        service.setInputs(oldInputs);
+
+        assertEquals(result.left().value(), defaultValue);
+    }
+
+    private ComponentInstance createComponetInstanceFromComponent(Component component) {
+        ComponentInstance componentInst = new ComponentInstance();
+        componentInst.setUniqueId(component.getUniqueId());
+        componentInst.setComponentUid(component.getUniqueId() + "_test");
+        componentInst.setPosX("10");
+        componentInst.setPosY("10");
+        componentInst.setCapabilities(component.getCapabilities());
+        componentInst.setRequirements(component.getRequirements());
+        componentInst.setArtifacts(component.getArtifacts());
+        componentInst.setDeploymentArtifacts(component.getDeploymentArtifacts());
+        return componentInst;
+    }
 }
index 0c91b49..d8e7896 100644 (file)
@@ -1,6 +1,10 @@
 package org.openecomp.sdc.be.servlets;
 
 import fj.data.Either;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.ws.rs.client.Entity;
 import org.eclipse.jetty.http.HttpStatus;
 import org.glassfish.hk2.utilities.binding.AbstractBinder;
 import org.glassfish.jersey.server.ResourceConfig;
@@ -16,7 +20,10 @@ import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
 import org.openecomp.sdc.be.impl.ComponentsUtils;
 import org.openecomp.sdc.be.impl.ServletUtils;
 import org.openecomp.sdc.be.impl.WebAppContextWrapper;
+import org.openecomp.sdc.be.model.CapabilityDefinition;
+import org.openecomp.sdc.be.model.ComponentInstance;
 import org.openecomp.sdc.be.model.RequirementCapabilityRelDef;
+import org.openecomp.sdc.be.model.RequirementDefinition;
 import org.openecomp.sdc.common.api.Constants;
 import org.openecomp.sdc.exception.ResponseFormat;
 import org.springframework.context.ApplicationContext;
@@ -31,6 +38,7 @@ import javax.ws.rs.core.Response;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.when;
 
@@ -94,6 +102,36 @@ public class ComponentInstanceServletTest extends JerseyTest {
         assertEquals(response.getStatus(), HttpStatus.BAD_REQUEST_400);
     }
 
+    @Test
+    public void testCopyComponentInstanceSuccess(){
+
+        String componentId = "componentId";
+        String componentInstanceId = "componentInstanceId";
+        String path = "/v1/catalog/services/" + componentId + "/copyComponentInstance/" + componentInstanceId;
+
+        Either<Map<String, ComponentInstance>, ResponseFormat> successResponse = Either.left(new HashMap<String, ComponentInstance>());
+        when(componentInstanceBusinessLogic.copyComponentInstance(any(ComponentInstance.class), eq(componentId), eq(componentInstanceId), eq(USER_ID))).thenReturn(successResponse);
+        when(responseFormat.getStatus()).thenReturn(HttpStatus.OK_200);
+        when(componentsUtils.getResponseFormat(ActionStatus.OK)).thenReturn(responseFormat);
+
+        ComponentInstance c = new ComponentInstance();
+        c.setName("comp1");
+        c.setUniqueId("comp1");
+        c.setComponentUid("comp1");
+        c.setPosX("10");
+        c.setPosY("10");
+        c.setCapabilities(new HashMap<String, List<CapabilityDefinition>>());
+        c.setRequirements(new HashMap<String, List<RequirementDefinition>>());
+
+        Response response = target()
+            .path(path)
+            .request(MediaType.APPLICATION_JSON)
+            .header("USER_ID", USER_ID)
+            .post(Entity.json(c));
+
+        assertEquals(response.getStatus(), HttpStatus.OK_200);
+    }
+
     @Override
     protected ResourceConfig configure() {
         forceSet(TestProperties.CONTAINER_PORT, "0");
index 7acd65f..e5caee5 100644 (file)
@@ -23,7 +23,7 @@ package org.openecomp.sdc.be.dao.api;
 public enum ActionStatus {
     OK, ACCEPTED, CREATED, NO_CONTENT, GENERAL_ERROR, NOT_ALLOWED, MISSING_INFORMATION, RESTRICTED_OPERATION, RESTRICTED_ACCESS, INVALID_CONTENT,
     // User related
-    USER_ALREADY_EXIST, USER_INACTIVE, USER_NOT_FOUND, USER_HAS_ACTIVE_ELEMENTS, INVALID_EMAIL_ADDRESS, INVALID_ROLE, DELETE_USER_ADMIN_CONFLICT, UPDATE_USER_ADMIN_CONFLICT, CANNOT_DELETE_USER_WITH_ACTIVE_ELEMENTS, CANNOT_UPDATE_USER_WITH_ACTIVE_ELEMENTS, INVALID_USER_ID,
+    USER_ALREADY_EXIST, USER_INACTIVE, USER_NOT_FOUND, USER_HAS_ACTIVE_ELEMENTS, INVALID_EMAIL_ADDRESS, INVALID_ROLE, DELETE_USER_ADMIN_CONFLICT, UPDATE_USER_ADMIN_CONFLICT, CANNOT_DELETE_USER_WITH_ACTIVE_ELEMENTS, CANNOT_UPDATE_USER_WITH_ACTIVE_ELEMENTS, INVALID_USER_ID, USER_DEFINED,
     // CapabilityType related
     CAPABILITY_TYPE_ALREADY_EXIST, MISSING_CAPABILITY_TYPE, MISSING_CAPABILITIES, REQ_CAP_NOT_SATISFIED_BEFORE_CERTIFICATION, IMPORT_DUPLICATE_REQ_CAP_NAME, IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED,
     CAPABILITY_OF_INSTANCE_NOT_FOUND_ON_CONTAINER, REQUIREMENT_OF_INSTANCE_NOT_FOUND_ON_CONTAINER, RELATION_NOT_FOUND,
index eb41232..fda20c1 100644 (file)
@@ -1972,6 +1972,18 @@ public class NodeTemplateOperation extends BaseOperation {
         return updateToscaDataDeepElementsOfToscaElement(containerComponent.getUniqueId(), EdgeLabelEnum.INST_PROPERTIES, VertexTypeEnum.INST_PROPERTIES, properties, pathKeys, JsonPresentationFields.NAME);
     }
 
+    public StorageOperationStatus updateComponentInstanceAttribute(Component containerComponent, String componentInstanceId, ComponentInstanceProperty property){
+        List<String> pathKeys = new ArrayList<>();
+        pathKeys.add(componentInstanceId);
+        return updateToscaDataDeepElementOfToscaElement(containerComponent.getUniqueId(), EdgeLabelEnum.INST_ATTRIBUTES, VertexTypeEnum.INST_ATTRIBUTES, property, pathKeys, JsonPresentationFields.NAME);
+    }
+
+    public StorageOperationStatus addComponentInstanceAttribute(Component containerComponent, String componentInstanceId, ComponentInstanceProperty property){
+        List<String> pathKeys = new ArrayList<>();
+        pathKeys.add(componentInstanceId);
+        return addToscaDataDeepElementToToscaElement(containerComponent.getUniqueId(), EdgeLabelEnum.INST_ATTRIBUTES, VertexTypeEnum.INST_ATTRIBUTES, property, pathKeys, JsonPresentationFields.NAME);
+    }
+
     public StorageOperationStatus updateComponentInstanceInput(Component containerComponent, String componentInstanceId, ComponentInstanceInput property) {
 
         List<String> pathKeys = new ArrayList<>();
index aae7384..a1d08a6 100644 (file)
@@ -2222,6 +2222,14 @@ public class ToscaOperationFacade {
         return nodeTemplateOperation.addComponentInstanceProperty(containerComponent, componentInstanceId, property);
     }
 
+    public StorageOperationStatus updateComponentInstanceAttribute(Component containerComponent, String componentInstanceId, ComponentInstanceProperty property){
+        return nodeTemplateOperation.updateComponentInstanceAttribute(containerComponent, componentInstanceId, property);
+    }
+
+    public StorageOperationStatus addComponentInstanceAttribute(Component containerComponent, String componentInstanceId, ComponentInstanceProperty property){
+        return nodeTemplateOperation.addComponentInstanceAttribute(containerComponent, componentInstanceId, property);
+    }
+
     public StorageOperationStatus updateComponentInstanceInput(Component containerComponent, String componentInstanceId, ComponentInstanceInput property) {
         return nodeTemplateOperation.updateComponentInstanceInput(containerComponent, componentInstanceId, property);
     }