Maintain VFC instance attribute outputs on instance version change 10/129410/6
authorJvD_Ericsson <jeff.van.dam@est.tech>
Mon, 23 May 2022 07:26:40 +0000 (08:26 +0100)
committerMichael Morris <michael.morris@est.tech>
Fri, 3 Jun 2022 12:20:16 +0000 (12:20 +0000)
Issue-ID: SDC-4025
Signed-off-by: JvD_Ericsson <jeff.van.dam@est.tech>
Change-Id: Ia44a6ac73d9a52042caaacf0c5f790e1e2fc73f1

15 files changed:
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java
catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceAttributesAndOutputsMerge.java [new file with mode: 0644]
catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceAttributesMergeBL.java [new file with mode: 0644]
catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceMergeDataBusinessLogic.java
catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceOutputsRedeclareHandler.java [new file with mode: 0644]
catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/DataForMergeHolder.java
catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/output/DeclaredOutputsResolver.java [new file with mode: 0644]
catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/output/OutputsValuesMergingBusinessLogic.java [new file with mode: 0644]
catalog-be/src/test/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceAttributesAndOutputsMergeTest.java [new file with mode: 0644]
catalog-be/src/test/java/org/openecomp/sdc/be/components/utils/ComponentBuilder.java
catalog-be/src/test/java/org/openecomp/sdc/be/components/utils/ObjectGenerator.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/Component.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/AttributeDataDefinition.java
common-be/src/main/java/org/openecomp/sdc/be/utils/AttributeDefinitionUtils.java [new file with mode: 0644]

index 392020b..2caa721 100644 (file)
@@ -2936,13 +2936,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                 } else {
                     origComponent = getOriginComponentFromComponentInstance(newComponentInstance);
                     newComponentInstance.setName(resResourceInfo.getName());
-                    final Either<Component, StorageOperationStatus> getComponentRes = toscaOperationFacade
-                            .getToscaFullElement(newComponentInstance.getComponentUid());
-                    if (getComponentRes.isRight()) {
-                        throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(getComponentRes.right().value()));
-                    }
-                    final Component component = getComponentRes.left().value();
-                    final Map<String, InterfaceDefinition> componentInterfaces = component.getInterfaces();
+                    final Map<String, InterfaceDefinition> componentInterfaces = origComponent.getInterfaces();
                     if (MapUtils.isNotEmpty(componentInterfaces)) {
                         componentInterfaces.forEach(newComponentInstance::addInterface);
                     }
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceAttributesAndOutputsMerge.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceAttributesAndOutputsMerge.java
new file mode 100644 (file)
index 0000000..c1ab30d
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+* ============LICENSE_START=======================================================
+* SDC
+* ================================================================================
+* Copyright (C) 2022 Nordix Foundation. All rights reserved.
+* ================================================================================
+* 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.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* ============LICENSE_END=========================================================
+*/
+package org.openecomp.sdc.be.components.merge.instance;
+
+import fj.data.Either;
+import java.util.List;
+import java.util.ArrayList;
+import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
+import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.impl.ComponentsUtils;
+import org.openecomp.sdc.be.model.Component;
+import org.openecomp.sdc.be.model.ComponentInstance;
+import org.openecomp.sdc.be.model.ComponentInstanceAttribute;
+import org.openecomp.sdc.be.model.ComponentParametersView;
+import org.openecomp.sdc.be.model.OutputDefinition;
+import org.openecomp.sdc.be.model.User;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
+import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
+import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
+import org.openecomp.sdc.common.log.wrappers.Logger;
+
+
+
+import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
+
+@org.springframework.stereotype.Component("ComponentInstanceAttributesMerge")
+public class ComponentInstanceAttributesAndOutputsMerge implements ComponentInstanceMergeInterface {
+
+    private static final Logger log = Logger.getLogger(ComponentInstanceAttributesAndOutputsMerge.class);
+    private final ToscaOperationFacade toscaOperationFacade;
+    private final ComponentsUtils componentsUtils;
+    private final ComponentInstanceAttributesMergeBL componentInstanceAttributesMergeBL;
+    private final ComponentInstanceOutputsRedeclareHandler instanceOutputsRedeclareHandler;
+
+    public ComponentInstanceAttributesAndOutputsMerge(ToscaOperationFacade toscaOperationFacade, ComponentsUtils componentsUtils,
+                                                      ComponentInstanceAttributesMergeBL componentInstanceAttributesMergeBL,
+                                                      ComponentInstanceOutputsRedeclareHandler instanceOutputsRedeclareHandler) {
+        this.toscaOperationFacade = toscaOperationFacade;
+        this.componentsUtils = componentsUtils;
+        this.componentInstanceAttributesMergeBL = componentInstanceAttributesMergeBL;
+        this.instanceOutputsRedeclareHandler = instanceOutputsRedeclareHandler;
+    }
+
+
+    @Override
+    public void saveDataBeforeMerge(DataForMergeHolder dataHolder, Component containerComponent, ComponentInstance currentResourceInstance,
+                                    Component originComponent) {
+        dataHolder.setOrigComponentInstanceAttributes(containerComponent.safeGetComponentInstancesAttributes()
+            .get(currentResourceInstance.getUniqueId()));
+        dataHolder.setOrigComponentOutputs(containerComponent.getOutputs());
+    }
+
+
+    @Override
+    public Component mergeDataAfterCreate(User user, DataForMergeHolder dataHolder, Component updatedContainerComponent, String newInstanceId) {
+        Either<List<ComponentInstanceAttribute>, ActionStatus> attributesEither = mergeComponentInstanceAttributesIntoContainer(dataHolder,
+            updatedContainerComponent, newInstanceId);
+        if (attributesEither.isRight()) {
+            ActionStatus actionStatus = attributesEither.right().value();
+            throw new ByActionStatusComponentException(actionStatus);
+        }
+        Either<List<OutputDefinition>, ActionStatus> outputsEither = mergeComponentOutputsIntoContainer(dataHolder,
+                updatedContainerComponent.getUniqueId(), newInstanceId);
+        if (outputsEither.isRight()) {
+            ActionStatus actionStatus = outputsEither.right().value();
+            throw new ByActionStatusComponentException(actionStatus);
+        }
+        return updatedContainerComponent;
+    }
+
+    private Either<List<ComponentInstanceAttribute>, ActionStatus> mergeComponentInstanceAttributesIntoContainer(DataForMergeHolder dataHolder,
+                                                                                                                 Component updatedComponent,
+                                                                                                                 String instanceId) {
+        List<ComponentInstanceAttribute> originComponentInstanceAttributes = dataHolder.getOrigComponentInstanceAttributes();
+        List<ComponentInstanceAttribute> newComponentInstancesAttributes = updatedComponent.safeGetComponentInstanceAttributes(instanceId);
+        ActionStatus actionStatus = componentInstanceAttributesMergeBL
+            .mergeComponentInstanceAttributes(originComponentInstanceAttributes, updatedComponent, instanceId);
+        if (actionStatus != ActionStatus.OK) {
+            log.error(EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR, updatedComponent.getName(),
+                "Failed to update component " + updatedComponent.getName() + " " + instanceId
+                    + " with instance attributes " + newComponentInstancesAttributes);
+            return Either.right(actionStatus);
+        }
+        return Either.left(newComponentInstancesAttributes);
+    }
+
+    private Either<List<OutputDefinition>, ActionStatus> mergeComponentOutputsIntoContainer(DataForMergeHolder dataHolder,
+                                                                                            String newContainerComponentId, String newInstanceId) {
+        List<OutputDefinition> origComponentOutputs = dataHolder.getOrigComponentOutputs();
+        List<OutputDefinition> outputsToAddToContainer = new ArrayList<>();
+        if (isNotEmpty(origComponentOutputs)) {
+            Either<Component, StorageOperationStatus> componentWithInstancesAttributesAndOutputs = getComponentOutputs(newContainerComponentId);
+            if (componentWithInstancesAttributesAndOutputs.isRight()) {
+                log.error(EcompLoggerErrorCode.DATA_ERROR, newContainerComponentId, "Component " + newContainerComponentId
+                        + " was not found");
+                return Either.right(componentsUtils.convertFromStorageResponse(componentWithInstancesAttributesAndOutputs.right().value()));
+            }
+            Component updatedContainerComponent = componentWithInstancesAttributesAndOutputs.left().value();
+            ActionStatus redeclareStatus = instanceOutputsRedeclareHandler
+                .redeclareComponentOutputsForInstance(updatedContainerComponent, newInstanceId, origComponentOutputs);
+
+            if (redeclareStatus != ActionStatus.OK) {
+                log.error(EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR, updatedContainerComponent.getName(),
+                    "Failed to update component " + updatedContainerComponent.getName() + " " + newContainerComponentId
+                        + " with merged inputs " + outputsToAddToContainer);
+                return Either.right(redeclareStatus);
+            }
+        }
+        return Either.left(outputsToAddToContainer);
+    }
+
+    private Either<Component, StorageOperationStatus> getComponentOutputs(String containerComponentId) {
+        ComponentParametersView filter = new ComponentParametersView(true);
+        filter.setIgnoreComponentInstances(false);
+        filter.setIgnoreOutputs(false);
+        filter.setIgnoreComponentInstancesAttributes(false);
+        filter.setIgnoreArtifacts(false);
+        return toscaOperationFacade.getToscaElement(containerComponentId, filter);
+    }
+}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceAttributesMergeBL.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceAttributesMergeBL.java
new file mode 100644 (file)
index 0000000..5ee91f6
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2022 Nordix Foundation. All rights reserved.
+ * ================================================================================
+ * 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.sdc.be.components.merge.instance;
+
+import static org.openecomp.sdc.be.components.merge.resource.ResourceDataMergeBusinessLogic.ANY_ORDER_COMMAND;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.impl.ComponentsUtils;
+import org.openecomp.sdc.be.model.Component;
+import org.openecomp.sdc.be.model.ComponentInstanceAttribute;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
+import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
+import org.springframework.core.annotation.Order;
+
+@org.springframework.stereotype.Component
+@Order(ANY_ORDER_COMMAND)
+public class ComponentInstanceAttributesMergeBL {
+
+    private final ToscaOperationFacade toscaOperationFacade;
+    private final ComponentsUtils componentsUtils;
+
+    public ComponentInstanceAttributesMergeBL(ToscaOperationFacade toscaOperationFacade, ComponentsUtils componentsUtils) {
+        this.toscaOperationFacade = toscaOperationFacade;
+        this.componentsUtils = componentsUtils;
+    }
+
+    public ActionStatus mergeComponentInstanceAttributes(List<ComponentInstanceAttribute> oldInstAttributes,
+                                                         Component newComponent, String instanceId) {
+        List<ComponentInstanceAttribute> newInstAttributes = newComponent.safeGetComponentInstanceAttributes(instanceId);
+        if (newInstAttributes == null) {
+            return ActionStatus.OK;
+        }
+        List<ComponentInstanceAttribute> commonInstAttributes = new ArrayList<>();
+        newInstAttributes.forEach(newAttribute -> oldInstAttributes
+                .stream().filter(oldAttribute -> newAttribute.getName().equals(oldAttribute.getName())).forEach(oldInstAttribute -> {
+                    if ((oldInstAttribute.getValue() == null || oldInstAttribute.getValue().equals(oldInstAttribute.getDefaultValue()))
+                            && newAttribute.getDefaultValue() != null) {
+                        oldInstAttribute.setValue(newAttribute.getDefaultValue());
+                        oldInstAttribute.setDefaultValue(newAttribute.getDefaultValue());
+                    }
+                    oldInstAttribute.setDescription(newAttribute.getDescription());
+                    commonInstAttributes.add(oldInstAttribute);
+                }));
+        return updateComponentInstanceAttributes(newComponent, instanceId, commonInstAttributes);
+    }
+
+    private ActionStatus updateComponentInstanceAttributes(Component component, String instanceId, List<ComponentInstanceAttribute> newInstAttributes) {
+        StorageOperationStatus storageOperationStatus = toscaOperationFacade.updateComponentInstanceAttributes(component, instanceId, newInstAttributes);
+        if (storageOperationStatus != StorageOperationStatus.OK) {
+            return componentsUtils.convertFromStorageResponse(storageOperationStatus);
+        }
+        return ActionStatus.OK;
+    }
+}
index 7353a12..51349c1 100644 (file)
@@ -103,6 +103,8 @@ public class ComponentInstanceMergeDataBusinessLogic {
         filter.setIgnoreArtifacts(false);
         filter.setIgnoreServicePath(false);
         filter.setIgnoreComponentInstancesInterfaces(false);
+        filter.setIgnoreComponentInstancesAttributes(false);
+        filter.setIgnoreOutputs(false);
         return toscaOperationFacade.getToscaElement(containerComponentId, filter);
     }
 }
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceOutputsRedeclareHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceOutputsRedeclareHandler.java
new file mode 100644 (file)
index 0000000..0c851f8
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2022 Nordix Foundation. All rights reserved.
+ * ================================================================================
+ * 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.sdc.be.components.merge.instance;
+
+import static java.util.stream.Collectors.toList;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+import org.openecomp.sdc.be.components.merge.output.DeclaredOutputsResolver;
+import org.openecomp.sdc.be.components.merge.output.OutputsValuesMergingBusinessLogic;
+import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.datatypes.elements.AttributeDataDefinition;
+import org.openecomp.sdc.be.impl.ComponentsUtils;
+import org.openecomp.sdc.be.model.Component;
+import org.openecomp.sdc.be.model.OutputDefinition;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
+import org.openecomp.sdc.common.log.wrappers.Logger;
+
+@org.springframework.stereotype.Component
+public class ComponentInstanceOutputsRedeclareHandler {
+
+    private static final Logger log = Logger.getLogger(ComponentInstanceOutputsRedeclareHandler.class);
+    private final DeclaredOutputsResolver declaredOutputsResolver;
+    private final ToscaOperationFacade toscaOperationFacade;
+    private final ComponentsUtils componentsUtils;
+    private final OutputsValuesMergingBusinessLogic outputsValuesMergingBusinessLogic;
+
+    public ComponentInstanceOutputsRedeclareHandler(DeclaredOutputsResolver declaredOutputsResolver, ToscaOperationFacade toscaOperationFacade,
+                                                    ComponentsUtils componentsUtils,
+                                                    OutputsValuesMergingBusinessLogic outputsValuesMergingBusinessLogic) {
+        this.declaredOutputsResolver = declaredOutputsResolver;
+        this.toscaOperationFacade = toscaOperationFacade;
+        this.componentsUtils = componentsUtils;
+        this.outputsValuesMergingBusinessLogic = outputsValuesMergingBusinessLogic;
+    }
+
+    public ActionStatus redeclareComponentOutputsForInstance(Component container, String newInstanceId, List<OutputDefinition> oldOutputs) {
+        log.debug(
+            "#redeclareComponentOutputsForInstance - getting outputs that were previously declared from instance {} and setting on current component {}",
+            newInstanceId, container.getUniqueId());
+        List<AttributeDataDefinition> allAttributesForInstance = getAllGetAttributesForInstance(container, newInstanceId);
+        List<OutputDefinition> previouslyDeclaredOutputs = declaredOutputsResolver
+            .getPreviouslyDeclaredOutputsToMerge(oldOutputs, allAttributesForInstance, newInstanceId);
+        outputsValuesMergingBusinessLogic.mergeComponentOutputs(oldOutputs, previouslyDeclaredOutputs);
+        return updateOutputs(container.getUniqueId(), previouslyDeclaredOutputs);
+    }
+
+    private List<AttributeDataDefinition> getAllGetAttributesForInstance(Component newComponent, String instanceId) {
+        return Stream
+            .of(newComponent.safeGetComponentInstanceAttributes(instanceId))
+            .flatMap(Collection::stream).map(AttributeDataDefinition::new).collect(toList());
+    }
+
+    private ActionStatus updateOutputs(String containerId, List<OutputDefinition> outputsToUpdate) {
+        log.debug("#updateInputs - updating inputs for container {}", containerId);
+        return toscaOperationFacade.updateOutputsToComponent(outputsToUpdate, containerId)
+            .either(updatedInputs -> ActionStatus.OK, componentsUtils::convertFromStorageResponse);
+    }
+}
index 623d86e..21c7461 100644 (file)
@@ -28,10 +28,12 @@ import java.util.Optional;
 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.ComponentInstanceAttribute;
 import org.openecomp.sdc.be.model.ComponentInstanceInput;
 import org.openecomp.sdc.be.model.ComponentInstanceInterface;
 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
 import org.openecomp.sdc.be.model.InputDefinition;
+import org.openecomp.sdc.be.model.OutputDefinition;
 
 /**
  * Created by chaya on 9/7/2017.
@@ -52,10 +54,14 @@ public class DataForMergeHolder {
     private String origComponentInstId;
     private List<ComponentInstanceInterface> origComponentInstanceInterfaces;
     private Map<String, Integer> componentInstanceDeploymentArtifactsTimeOut;
+    private final List<ComponentInstanceAttribute> origComponentInstanceAttributes;
+    private final List<OutputDefinition> origComponentOutputs;
 
     public DataForMergeHolder() {
         origComponentInstanceInputs = new ArrayList<>();
         origComponentInstanceProperties = new ArrayList<>();
+        origComponentInstanceAttributes = new ArrayList<>();
+        origComponentOutputs = new ArrayList<>();
         origComponentInputs = new ArrayList<>();
         origCompInstDeploymentArtifactsCreatedOnTheInstance = new HashMap<>();
         origCompInstDeploymentArtifactsCreatedOnTheInstance = new HashMap<>();
@@ -77,7 +83,7 @@ public class DataForMergeHolder {
     }
 
     void setOrigComponentInstanceInputs(List<ComponentInstanceInput> origComponentInstanceInputs) {
-        Optional.ofNullable(origComponentInstanceInputs).orElse(Collections.emptyList()).stream().forEach(input -> {
+        Optional.ofNullable(origComponentInstanceInputs).orElse(Collections.emptyList()).forEach(input -> {
             ComponentInstanceInput copyInput = new ComponentInstanceInput();
             copyInput.setType(input.getType());
             copyInput.setPath(input.getPath());
@@ -107,7 +113,7 @@ public class DataForMergeHolder {
     }
 
     void setOrigComponentInstanceProperties(List<ComponentInstanceProperty> origComponentInstanceProperties) {
-        Optional.ofNullable(origComponentInstanceProperties).orElse(Collections.emptyList()).stream().forEach(property -> {
+        Optional.ofNullable(origComponentInstanceProperties).orElse(Collections.emptyList()).forEach(property -> {
             ComponentInstanceProperty propertyCopy = new ComponentInstanceProperty();
             propertyCopy.setType(property.getType());
             propertyCopy.setName(property.getName());
@@ -207,4 +213,42 @@ public class DataForMergeHolder {
     public void setOrigComponentInstanceInterfaces(List<ComponentInstanceInterface> origComponentInstanceInterfaces) {
         this.origComponentInstanceInterfaces = origComponentInstanceInterfaces;
     }
+
+    List<ComponentInstanceAttribute> getOrigComponentInstanceAttributes() {
+        return origComponentInstanceAttributes;
+    }
+
+    void setOrigComponentInstanceAttributes(List<ComponentInstanceAttribute> origComponentInstanceAttributes) {
+        Optional.ofNullable(origComponentInstanceAttributes).orElse(Collections.emptyList()).forEach(attribute -> {
+            ComponentInstanceAttribute attributeCopy = new ComponentInstanceAttribute();
+            attributeCopy.setType(attribute.getType());
+            attributeCopy.setName(attribute.getName());
+            attributeCopy.setValue(attribute.getValue());
+            attributeCopy.setUniqueId(attribute.getUniqueId());
+            attributeCopy.setDefaultValue(attribute.getDefaultValue());
+            attributeCopy.setOutputId(attribute.getOutputId());
+            attributeCopy.setGetOutputValues(attribute.getGetOutputValues());
+            attributeCopy.setOutputPath(attribute.getOutputPath());
+            this.origComponentInstanceAttributes.add(attributeCopy);
+        });
+    }
+
+    List<OutputDefinition> getOrigComponentOutputs() {
+        return origComponentOutputs;
+    }
+
+    void setOrigComponentOutputs(List<OutputDefinition> origComponentOutputs) {
+        Optional.ofNullable(origComponentOutputs).orElse(Collections.emptyList()).forEach(output -> {
+            OutputDefinition outputCopy = new OutputDefinition();
+            outputCopy.setType(output.getType());
+            outputCopy.setName(output.getName());
+            outputCopy.setValue(output.getValue());
+            outputCopy.setUniqueId(output.getUniqueId());
+            outputCopy.setDefaultValue(output.getDefaultValue());
+            outputCopy.setOutputId(output.getOutputId());
+            outputCopy.setGetOutputValues(output.getGetOutputValues());
+            outputCopy.setOutputPath(output.getOutputPath());
+            this.origComponentOutputs.add(outputCopy);
+        });
+    }
 }
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/output/DeclaredOutputsResolver.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/output/DeclaredOutputsResolver.java
new file mode 100644 (file)
index 0000000..e48779a
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2022 Nordix Foundation. All rights reserved.
+ * ================================================================================
+ * 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.sdc.be.components.merge.output;
+
+import static org.openecomp.sdc.be.utils.AttributeDefinitionUtils.getAttributesMappedToOutputs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.openecomp.sdc.be.dao.utils.MapUtil;
+import org.openecomp.sdc.be.datatypes.elements.AttributeDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.GetOutputValueDataDefinition;
+import org.openecomp.sdc.be.model.OutputDefinition;
+
+@org.springframework.stereotype.Component
+public class DeclaredOutputsResolver {
+
+    public List<OutputDefinition> getPreviouslyDeclaredOutputsToMerge(List<OutputDefinition> oldOutputs, List<AttributeDataDefinition> attributes,
+                                                                      String instanceId) {
+        List<AttributeDataDefinition> attributesMappedToOutputsOnNewInstance = getAttributesMappedToOutputs(attributes);
+        return createOutputs(oldOutputs, attributesMappedToOutputsOnNewInstance, instanceId);
+    }
+
+    private List<OutputDefinition> createOutputs(List<OutputDefinition> oldOutputs,
+                                                 List<AttributeDataDefinition> attributesMappedToOutputsOnNewInstance, String instanceId) {
+        Map<String, OutputDefinition> oldOutputsById = MapUtil.toMap(oldOutputs, OutputDefinition::getUniqueId);
+        List<OutputDefinition> outputsToRedeclare = new ArrayList<>();
+        attributesMappedToOutputsOnNewInstance.forEach(attribute -> {
+            List<OutputDefinition> outputDefinitions = prepareOutputsForRedeclaration(oldOutputsById, attribute, instanceId);
+            outputsToRedeclare.addAll(outputDefinitions);
+        });
+        return outputsToRedeclare;
+    }
+
+    private List<OutputDefinition> prepareOutputsForRedeclaration(Map<String, OutputDefinition> oldOutputsById,
+                                                                  AttributeDataDefinition attributeToCreateOutputFor, String instanceID) {
+        List<GetOutputValueDataDefinition> getOutputValueDataDefinition = attributeToCreateOutputFor.getGetOutputValues();
+        List<OutputDefinition> outputsForRedeclaration = new ArrayList<>();
+        for (GetOutputValueDataDefinition out : getOutputValueDataDefinition) {
+            if (oldOutputsById.containsKey(out.getOutputId())) {
+                OutputDefinition test = oldOutputsById.get(out.getOutputId());
+                test.setAttributeId(attributeToCreateOutputFor.getUniqueId());
+                test.setInstanceUniqueId(instanceID);
+                outputsForRedeclaration.add(test);
+            }
+        }
+        return outputsForRedeclaration;
+    }
+}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/output/OutputsValuesMergingBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/output/OutputsValuesMergingBusinessLogic.java
new file mode 100644 (file)
index 0000000..888672c
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2022 Nordix Foundation. All rights reserved.
+ * ================================================================================
+ * 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.sdc.be.components.merge.output;
+
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.lang3.StringUtils;
+import org.openecomp.sdc.be.dao.utils.MapUtil;
+import org.openecomp.sdc.be.model.OutputDefinition;
+import org.springframework.stereotype.Component;
+
+@Component
+public class OutputsValuesMergingBusinessLogic {
+
+    public void mergeComponentOutputs(List<OutputDefinition> oldOutputs, List<OutputDefinition> outputsToMerge) {
+        Map<String, OutputDefinition> oldOutputsByName = MapUtil.toMap(oldOutputs, OutputDefinition::getName);
+        Map<String, OutputDefinition> outputsToMergeByName = MapUtil.toMap(outputsToMerge, OutputDefinition::getName);
+        mergeComponentOutputs(oldOutputsByName, outputsToMergeByName);
+    }
+
+    public void mergeComponentOutputs(Map<String, OutputDefinition> oldOutputs, Map<String, OutputDefinition> updatedOutputs) {
+        updatedOutputs.forEach((outputName, output) -> mergeOutputsValues(oldOutputs.get(outputName), output));
+    }
+
+    private void mergeOutputsValues(OutputDefinition oldOutput, OutputDefinition updatedOutput) {
+        if (shouldMergeOldValue(oldOutput, updatedOutput)) {
+            updatedOutput.setDefaultValue(oldOutput.getDefaultValue());
+        }
+    }
+
+    private boolean shouldMergeOldValue(OutputDefinition oldOutput, OutputDefinition newOutput) {
+        return isNonEmptyDefaultValue(oldOutput) && isEmptyDefaultValue(newOutput) && isSameType(oldOutput, newOutput);
+    }
+
+    private boolean isSameType(OutputDefinition oldOutput, OutputDefinition updatedOutput) {
+        return oldOutput.typeEquals(updatedOutput);
+    }
+
+    private boolean isEmptyDefaultValue(OutputDefinition output) {
+        return output != null && StringUtils.isEmpty(output.getDefaultValue());
+    }
+
+    private boolean isNonEmptyDefaultValue(OutputDefinition output) {
+        return output != null && !isEmptyDefaultValue(output);
+    }
+}
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceAttributesAndOutputsMergeTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceAttributesAndOutputsMergeTest.java
new file mode 100644 (file)
index 0000000..931469a
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2022 Nordix Foundation. All rights reserved.
+ * ================================================================================
+ * 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdc.be.components.merge.instance;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+
+import fj.data.Either;
+import java.util.List;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
+import org.openecomp.sdc.be.components.utils.ObjectGenerator;
+import org.openecomp.sdc.be.components.utils.ResourceBuilder;
+import org.openecomp.sdc.be.config.ConfigurationManager;
+import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.impl.ComponentsUtils;
+import org.openecomp.sdc.be.model.Component;
+import org.openecomp.sdc.be.model.ComponentInstanceAttribute;
+import org.openecomp.sdc.be.model.ComponentParametersView;
+import org.openecomp.sdc.be.model.OutputDefinition;
+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.jsonjanusgraph.operations.ToscaOperationFacade;
+import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
+import org.openecomp.sdc.common.impl.ExternalConfiguration;
+import org.openecomp.sdc.common.impl.FSConfigurationSource;
+import org.openecomp.sdc.exception.ResponseFormat;
+
+class ComponentInstanceAttributesAndOutputsMergeTest {
+
+    private static final String INSTANCE_ID1 = "inst1";
+    private static final User USER = new User();
+
+    @InjectMocks
+    private ComponentInstanceAttributesAndOutputsMerge testInstance;
+
+    @Mock
+    private ToscaOperationFacade toscaOperationFacade;
+
+    @Mock
+    private ComponentsUtils componentsUtils;
+
+    @Mock
+    private ComponentInstanceAttributesMergeBL componentInstanceAttributesMergeBL;
+
+    @Mock
+    private ComponentInstanceOutputsRedeclareHandler componentInstanceOutputsRedeclareHandler;
+
+    private Resource resourceToUpdate;
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        MockitoAnnotations.openMocks(this);
+        resourceToUpdate = new ResourceBuilder()
+            .addInstanceAttribute(INSTANCE_ID1, "instAttribute1")
+            .addInstanceAttribute(INSTANCE_ID1, "instAttribute2")
+            .addOutput("output1")
+            .addOutput("output2")
+            .setUniqueId("resourceId").build();
+
+        List<OutputDefinition> oldOutputs = ObjectGenerator.buildOutputs("output1");
+        List<ComponentInstanceAttribute> oldInstAttribute = ObjectGenerator.buildInstanceAttributes("instAttribute1", "instAttribute3");
+
+        DataForMergeHolder oldDataHolder = new DataForMergeHolder();
+        oldDataHolder.setOrigComponentOutputs(oldOutputs);
+        oldDataHolder.setOrigComponentInstanceAttributes(oldInstAttribute);
+        new ConfigurationManager(new FSConfigurationSource(ExternalConfiguration.getChangeListener(), "src/test/resources/config/catalog-be"));
+    }
+
+    @Test
+    void mergeDataAfterCreate() {
+        List<OutputDefinition> oldOutputs = ObjectGenerator.buildOutputs("output1");
+        List<ComponentInstanceAttribute> oldInstAttributes = ObjectGenerator.buildInstanceAttributes("instAttribute1", "instAttribute3");
+
+        DataForMergeHolder dataForMergeHolder = new DataForMergeHolder();
+        dataForMergeHolder.setOrigComponentOutputs(oldOutputs);
+        dataForMergeHolder.setOrigComponentInstanceAttributes(oldInstAttributes);
+
+        ArgumentCaptor<ComponentParametersView> parametersViewCaptor = ArgumentCaptor.forClass(ComponentParametersView.class);
+
+       when(componentInstanceAttributesMergeBL.mergeComponentInstanceAttributes(anyList(), eq(resourceToUpdate), eq(INSTANCE_ID1)))
+                .thenReturn(ActionStatus.OK);
+        when(componentInstanceOutputsRedeclareHandler.redeclareComponentOutputsForInstance(any(), any(), anyList()))
+                .thenReturn(ActionStatus.OK);
+        when(toscaOperationFacade.getToscaElement(eq("resourceId"), parametersViewCaptor.capture()))
+                .thenReturn(Either.left(resourceToUpdate));
+        Component mergeResult = testInstance.mergeDataAfterCreate(USER, dataForMergeHolder, resourceToUpdate, INSTANCE_ID1);
+        assertEquals(mergeResult, resourceToUpdate);
+        assertComponentFilter(parametersViewCaptor.getValue());
+    }
+
+    @Test
+    void mergeDataAfterCreate_failedToMergeComponentInstanceOutputs() {
+        List<OutputDefinition> oldOutputs = ObjectGenerator.buildOutputs("output1");
+        List<ComponentInstanceAttribute> oldInstAttributes = ObjectGenerator.buildInstanceAttributes("instAttribute1", "instAttribute3");
+
+        DataForMergeHolder dataForMergeHolder = new DataForMergeHolder();
+        dataForMergeHolder.setOrigComponentOutputs(oldOutputs);
+        dataForMergeHolder.setOrigComponentInstanceAttributes(oldInstAttributes);
+
+        ArgumentCaptor<ComponentParametersView> parametersViewCaptor = ArgumentCaptor.forClass(ComponentParametersView.class);
+
+        when(componentInstanceAttributesMergeBL.mergeComponentInstanceAttributes(anyList(), eq(resourceToUpdate), eq(INSTANCE_ID1)))
+                .thenReturn(ActionStatus.OK);
+        when(toscaOperationFacade.getToscaElement(eq("resourceId"), parametersViewCaptor.capture()))
+                .thenReturn(Either.right(StorageOperationStatus.GENERAL_ERROR));
+        when(componentsUtils.convertFromStorageResponse(StorageOperationStatus.GENERAL_ERROR)).thenReturn(ActionStatus.GENERAL_ERROR);
+        assertThrows(ComponentException.class, () -> {
+            testInstance.mergeDataAfterCreate(USER, dataForMergeHolder, resourceToUpdate, "inst1");
+        });
+        verifyNoInteractions(componentInstanceOutputsRedeclareHandler);
+    }
+
+    @Test
+    void mergeDataAfterCreate_failedToMergeComponentInstAttributes() {
+        final ResponseFormat errorResponse = new ResponseFormat();
+        when(componentInstanceAttributesMergeBL.mergeComponentInstanceAttributes(anyList(), any(Component.class), anyString()))
+            .thenReturn(ActionStatus.GENERAL_ERROR);
+        when(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)).thenReturn(errorResponse);
+        final DataForMergeHolder dataHolder = new DataForMergeHolder();
+        final Service service = new Service();
+        assertThrows(ComponentException.class, () -> {
+            testInstance.mergeDataAfterCreate(USER, dataHolder, service, "inst1");
+        });
+        verifyNoInteractions(componentInstanceOutputsRedeclareHandler, toscaOperationFacade);
+    }
+
+    @Test
+    void mergeDataAfterCreate_mergeInputs_FailedToFetchResource() {
+        final ResponseFormat errorResponse = new ResponseFormat();
+        when(componentInstanceAttributesMergeBL.mergeComponentInstanceAttributes(anyList(), any(Component.class), anyString()))
+            .thenReturn(ActionStatus.OK);
+        when(toscaOperationFacade.getToscaElement(any(), any(ComponentParametersView.class)))
+            .thenReturn(Either.right(StorageOperationStatus.GENERAL_ERROR));
+        when(componentsUtils.convertFromStorageResponse(StorageOperationStatus.GENERAL_ERROR)).thenReturn(ActionStatus.GENERAL_ERROR);
+        when(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)).thenReturn(errorResponse);
+        final DataForMergeHolder dataHolder = new DataForMergeHolder();
+        dataHolder.setOrigComponentOutputs(ObjectGenerator.buildOutputs("output1", "output2"));
+        final Service service = new Service();
+        assertThrows(ComponentException.class, () -> {
+            testInstance.mergeDataAfterCreate(USER, dataHolder, service, "inst1");
+        });
+        verifyNoInteractions(componentInstanceOutputsRedeclareHandler);
+    }
+
+    private void assertComponentFilter(ComponentParametersView value) {
+        assertFalse(value.isIgnoreComponentInstances());
+        assertFalse(value.isIgnoreComponentInstancesAttributes());
+        assertFalse(value.isIgnoreOutputs());
+        assertFalse(value.isIgnoreArtifacts());
+    }
+}
index 0dad76e..b9e181f 100644 (file)
@@ -25,7 +25,9 @@ import org.openecomp.sdc.be.datatypes.elements.GetInputValueDataDefinition;
 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
 import org.openecomp.sdc.be.model.Component;
 import org.openecomp.sdc.be.model.ComponentInstance;
+import org.openecomp.sdc.be.model.ComponentInstanceAttribute;
 import org.openecomp.sdc.be.model.ComponentInstanceInput;
+import org.openecomp.sdc.be.model.ComponentInstanceOutput;
 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
 import org.openecomp.sdc.be.model.GroupDefinition;
 import org.openecomp.sdc.be.model.InputDefinition;
@@ -37,6 +39,7 @@ import org.openecomp.sdc.be.model.RequirementCapabilityRelDef;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 public abstract class ComponentBuilder<T extends Component, B extends ComponentBuilder<T, B>> {
 
@@ -190,6 +193,33 @@ public abstract class ComponentBuilder<T extends Component, B extends ComponentB
         return self();
     }
 
+    public void addInstanceAttribute(String instanceId, ComponentInstanceAttribute attribute) {
+        Map<String, List<ComponentInstanceAttribute>> compInstAttribute = component.safeGetComponentInstancesAttributes();
+        if (compInstAttribute == null || compInstAttribute.isEmpty()) {
+            component.setComponentInstancesAttributes(new HashMap<>());
+        }
+        Map<String, List<ComponentInstanceAttribute>> instAttribute = component.safeGetComponentInstancesAttributes();
+        instAttribute.computeIfAbsent(instanceId, key -> new ArrayList<>()).add(attribute);
+        self();
+    }
+
+    public ComponentBuilder<T, B> addInstanceAttribute(String instanceId, String AttributeName) {
+        ComponentInstanceAttribute componentInstanceAttribute = new ComponentInstanceAttribute();
+        componentInstanceAttribute.setName(AttributeName);
+        componentInstanceAttribute.setUniqueId(AttributeName);
+        this.addInstanceAttribute(instanceId, componentInstanceAttribute);
+        return self();
+    }
+
+    public void addInstanceOutput(String instanceId, ComponentInstanceOutput attribute) {
+        if (component.getComponentInstancesOutputs() == null) {
+            component.setComponentInstancesOutputs(new HashMap<>());
+        }
+        component.getComponentInstancesOutputs().computeIfAbsent(instanceId, key -> new ArrayList<>()).add(attribute);
+        self();
+    }
+
+
     public ComponentBuilder<T, B> addRelationship(RequirementCapabilityRelDef requirementCapabilityRelDef) {
         if (component.getComponentInstancesRelations() == null) {
             component.setComponentInstancesRelations(new ArrayList<>());
index c6a3697..8f194f1 100644 (file)
 package org.openecomp.sdc.be.components.utils;
 
 import org.openecomp.sdc.be.model.ComponentInstance;
+import org.openecomp.sdc.be.model.ComponentInstanceAttribute;
 import org.openecomp.sdc.be.model.ComponentInstanceInput;
 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
 import org.openecomp.sdc.be.model.HeatParameterDefinition;
 import org.openecomp.sdc.be.model.InputDefinition;
+import org.openecomp.sdc.be.model.OutputDefinition;
 import org.openecomp.sdc.be.model.PropertyDefinition;
 import org.openecomp.sdc.be.model.RequirementCapabilityRelDef;
 import org.openecomp.sdc.be.model.Resource;
@@ -80,6 +82,24 @@ public class ObjectGenerator {
         return inputs;
     }
 
+    public static List<ComponentInstanceAttribute> buildInstanceAttributes(String ... attributesNames) {
+        return Stream.of(attributesNames).map(name ->  {
+            ComponentInstanceAttribute instAttribute = new ComponentInstanceAttribute();
+            instAttribute.setName(name);
+            return instAttribute;
+        }).collect(Collectors.toList());
+    }
+
+    public static List<OutputDefinition> buildOutputs(String ... outputNames) {
+        List<OutputDefinition> outputs = new ArrayList<>();
+        for (String outputName : outputNames) {
+            OutputDefinition outputDefinition = new OutputDefinition();
+            outputDefinition.setName(outputName);
+            outputs.add(outputDefinition);
+        }
+        return outputs;
+    }
+
     public static Resource buildResourceWithComponentInstance(String ... instanceNames) {
         List<ComponentInstance> instances = new ArrayList<>();
         for (String instanceName : instanceNames) {
index 1c0cfc4..3252d79 100644 (file)
@@ -387,10 +387,18 @@ public abstract class Component implements PropertiesOwner {
         return this.safeGetComponentInstanceEntity(cmptInstacneId, this.componentInstancesProperties);
     }
 
+    public List<ComponentInstanceAttribute> safeGetComponentInstanceAttributes(String cmptInstacneId) {
+        return this.safeGetComponentInstanceEntity(cmptInstacneId, this.componentInstancesAttributes);
+    }
+
     public List<ComponentInstanceInput> safeGetComponentInstanceInput(String comptInstanceId) {
         return this.safeGetComponentInstanceEntity(comptInstanceId, this.componentInstancesInputs);
     }
 
+    public List<ComponentInstanceOutput> safeGetComponentInstanceOutput(String comptInstanceId) {
+        return this.safeGetComponentInstanceEntity(comptInstanceId, this.componentInstancesOutputs);
+    }
+
     public List<ComponentInstanceInterface> safeGetComponentInstanceInterfaces(String cmptInstacneId) {
         return this.safeGetComponentInstanceEntity(cmptInstacneId, this.componentInstancesInterfaces);
     }
index 09e0233..cf1b23e 100644 (file)
@@ -1517,6 +1517,27 @@ public class ToscaOperationFacade {
         return Either.right(status);
     }
 
+    public Either<List<OutputDefinition>, StorageOperationStatus> updateOutputsToComponent(List<OutputDefinition> outputs, String componentId) {
+        Either<GraphVertex, JanusGraphOperationStatus> getVertexEither = janusGraphDao.getVertexById(componentId, JsonParseFlagEnum.NoParse);
+        if (getVertexEither.isRight()) {
+            log.debug(COULDNT_FETCH_COMPONENT_WITH_AND_UNIQUE_ID_ERROR, componentId, getVertexEither.right().value());
+            return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(getVertexEither.right().value()));
+        }
+        GraphVertex vertex = getVertexEither.left().value();
+        List<AttributeDataDefinition> outputsAsDataDef = outputs.stream().map(AttributeDataDefinition::new).collect(Collectors.toList());
+        StorageOperationStatus status = topologyTemplateOperation
+                .updateToscaDataOfToscaElement(vertex, EdgeLabelEnum.OUTPUTS, VertexTypeEnum.OUTPUTS, outputsAsDataDef, JsonPresentationFields.NAME);
+        if (StorageOperationStatus.OK == status) {
+            log.debug(COMPONENT_CREATED_SUCCESSFULLY);
+            List<OutputDefinition> outputsResList = null;
+            if (!outputsAsDataDef.isEmpty()) {
+                outputsResList = outputsAsDataDef.stream().map(OutputDefinition::new).collect(Collectors.toList());
+            }
+            return Either.left(outputsResList);
+        }
+        return Either.right(status);
+    }
+
     // region - ComponentInstance
     public Either<Map<String, List<ComponentInstanceProperty>>, StorageOperationStatus> associateComponentInstancePropertiesToComponent(
         Map<String, List<ComponentInstanceProperty>> instProperties, String componentId) {
index ee78821..7e99418 100644 (file)
@@ -140,4 +140,26 @@ public class AttributeDataDefinition extends ToscaDataDefinition {
     public String getParentUniqueId() {
         return getOwnerId();
     }
+
+    public boolean isGetOutputAttribute() {
+        return this.getGetOutputValues() != null && !this.getGetOutputValues().isEmpty();
+    }
+
+    public boolean typeEquals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        AttributeDataDefinition other = (AttributeDataDefinition) obj;
+        if (this.getType() == null) {
+            return other.getType() == null;
+        }
+        return false;
+    }
+
 }
diff --git a/common-be/src/main/java/org/openecomp/sdc/be/utils/AttributeDefinitionUtils.java b/common-be/src/main/java/org/openecomp/sdc/be/utils/AttributeDefinitionUtils.java
new file mode 100644 (file)
index 0000000..00836e7
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2022 Nordix Foundation. All rights reserved.
+ * ================================================================================
+ * 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.sdc.be.utils;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.openecomp.sdc.be.datatypes.elements.AttributeDataDefinition;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class AttributeDefinitionUtils {
+
+    public static List<AttributeDataDefinition> getAttributesMappedToOutputs(List<AttributeDataDefinition> attributes) {
+        if (attributes == null) {
+            return Collections.emptyList();
+        }
+        return filterGetOutputAttributes(attributes);
+    }
+
+    private static <T extends AttributeDataDefinition> List<AttributeDataDefinition> filterGetOutputAttributes(List<T> attributeDefinitions) {
+        return attributeDefinitions.stream().filter(AttributeDataDefinition::isGetOutputAttribute).collect(Collectors.toList());
+    }
+}