Implement Attributes/Outputs BE (part 2)
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / OutputsBusinessLogic.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2021, Nordix Foundation. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.sdc.be.components.impl;
22
23 import fj.data.Either;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Optional;
28 import org.openecomp.sdc.be.components.attribute.AttributeDeclarationOrchestrator;
29 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
30 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
31 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
32 import org.openecomp.sdc.be.components.validation.ComponentValidations;
33 import org.openecomp.sdc.be.dao.api.ActionStatus;
34 import org.openecomp.sdc.be.dao.utils.MapUtil;
35 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
36 import org.openecomp.sdc.be.model.Component;
37 import org.openecomp.sdc.be.model.ComponentInstOutputsMap;
38 import org.openecomp.sdc.be.model.ComponentInstanceOutput;
39 import org.openecomp.sdc.be.model.ComponentParametersView;
40 import org.openecomp.sdc.be.model.OutputDefinition;
41 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
42 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
43 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
44 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
45 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
46 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
47 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
48 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
49 import org.openecomp.sdc.common.log.elements.LoggerSupportability;
50 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
51 import org.openecomp.sdc.common.log.enums.StatusCode;
52 import org.openecomp.sdc.common.log.wrappers.Logger;
53 import org.openecomp.sdc.exception.ResponseFormat;
54 import org.springframework.beans.factory.annotation.Autowired;
55
56 @org.springframework.stereotype.Component("outputsBusinessLogic")
57 public class OutputsBusinessLogic extends BaseBusinessLogic {
58
59     private static final String CREATE_OUTPUT = "CreateOutput";
60
61     private static final Logger log = Logger.getLogger(OutputsBusinessLogic.class);
62     private static final String FAILED_TO_FOUND_COMPONENT_ERROR = "Failed to found component {}, error: {}";
63     private static final String GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_GROUP = "Going to execute rollback on create group.";
64     private static final String GOING_TO_EXECUTE_COMMIT_ON_CREATE_GROUP = "Going to execute commit on create group.";
65     private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(OutputsBusinessLogic.class);
66     private static final String FAILED_TO_FOUND_COMPONENT_INSTANCE_OUTPUTS_COMPONENT_INSTANCE_ID = "Failed to found component instance outputs componentInstanceId: {}";
67     private static final String FAILED_TO_FOUND_COMPONENT_INSTANCE_OUTPUTS_ERROR = "Failed to found component instance outputs {}, error: {}";
68
69     private final AttributeDeclarationOrchestrator attributeDeclarationOrchestrator;
70
71     @Autowired
72     public OutputsBusinessLogic(final IElementOperation elementDao,
73                                 final IGroupOperation groupOperation,
74                                 final IGroupInstanceOperation groupInstanceOperation,
75                                 final IGroupTypeOperation groupTypeOperation,
76                                 final InterfaceOperation interfaceOperation,
77                                 final InterfaceLifecycleOperation interfaceLifecycleTypeOperation,
78                                 final AttributeDeclarationOrchestrator attributeDeclarationOrchestrator,
79                                 final ArtifactsOperations artifactToscaOperation) {
80         super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation,
81             artifactToscaOperation);
82         this.attributeDeclarationOrchestrator = attributeDeclarationOrchestrator;
83     }
84
85     public Either<List<ComponentInstanceOutput>, ResponseFormat> getComponentInstanceOutputs(final String userId,
86                                                                                              final String componentId,
87                                                                                              final String componentInstanceId) {
88
89         validateUserExists(userId);
90         final ComponentParametersView filters = new ComponentParametersView();
91         filters.disableAll();
92         filters.setIgnoreOutputs(false);
93         filters.setIgnoreComponentInstances(false);
94         filters.setIgnoreComponentInstancesOutputs(false);
95
96         final Either<Component, StorageOperationStatus> getComponentEither = toscaOperationFacade.getToscaElement(componentId, filters);
97         if(getComponentEither.isRight()){
98             ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
99             log.debug(FAILED_TO_FOUND_COMPONENT_ERROR, componentId, actionStatus);
100             return Either.right(componentsUtils.getResponseFormat(actionStatus));
101
102         }
103         final Component component = getComponentEither.left().value();
104
105         if (!ComponentValidations.validateComponentInstanceExist(component, componentInstanceId)) {
106             final ActionStatus actionStatus = ActionStatus.COMPONENT_INSTANCE_NOT_FOUND;
107             log.debug(FAILED_TO_FOUND_COMPONENT_INSTANCE_OUTPUTS_ERROR, componentInstanceId, actionStatus);
108             loggerSupportability.log(LoggerSupportabilityActions.CREATE_INPUTS, component.getComponentMetadataForSupportLog(),
109                 StatusCode.ERROR, FAILED_TO_FOUND_COMPONENT_INSTANCE_OUTPUTS_COMPONENT_INSTANCE_ID, componentInstanceId);
110             return Either.right(componentsUtils.getResponseFormat(actionStatus));
111         }
112         final Map<String, List<ComponentInstanceOutput>> ciOutputs = Optional.ofNullable(component.getComponentInstancesOutputs())
113             .orElse(Collections.emptyMap());
114
115         return Either.left(ciOutputs.getOrDefault(componentInstanceId, Collections.emptyList()));
116     }
117
118     @Override
119     public Either<List<OutputDefinition>, ResponseFormat> declareAttributes(final String userId,
120                                                                             final String componentId,
121                                                                             final ComponentTypeEnum componentTypeEnum,
122                                                                             final ComponentInstOutputsMap componentInstOutputsMap) {
123
124         return createMultipleOutputs(userId, componentId, componentTypeEnum, componentInstOutputsMap, true, false);
125     }
126
127     public Either<List<OutputDefinition>, ResponseFormat> createMultipleOutputs(final String userId,
128                                                                                 final String componentId,
129                                                                                 final ComponentTypeEnum componentType,
130                                                                                 final ComponentInstOutputsMap componentInstOutputsMapUi,
131                                                                                 final boolean shouldLockComp,
132                                                                                 final boolean inTransaction) {
133
134         Either<List<OutputDefinition>, ResponseFormat> result = null;
135         org.openecomp.sdc.be.model.Component component = null;
136
137         try {
138             validateUserExists(userId);
139
140             component = getAndValidateComponentForCreate(userId, componentId, componentType, shouldLockComp);
141
142             result = attributeDeclarationOrchestrator.declareAttributesToOutputs(component, componentInstOutputsMapUi)
143                 .left()
144                 .bind(outputsToCreate -> prepareOutputsForCreation(userId, componentId, outputsToCreate))
145                 .right()
146                 .map(componentsUtils::getResponseFormat);
147             return result;
148
149         } catch (final ByResponseFormatComponentException e) {
150             log.error("#createMultipleOutputs: Exception thrown: ", e);
151             result = Either.right(e.getResponseFormat());
152             return result;
153         } finally {
154
155             if (!inTransaction) {
156                 if (result == null || result.isRight()) {
157                     log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_GROUP);
158                     janusGraphDao.rollback();
159                 } else {
160                     log.debug(GOING_TO_EXECUTE_COMMIT_ON_CREATE_GROUP);
161                     janusGraphDao.commit();
162                 }
163             }
164             // unlock resource
165             if (shouldLockComp && component != null) {
166                 graphLockOperation.unlockComponent(componentId, componentType.getNodeType());
167             }
168
169         }
170     }
171
172     private org.openecomp.sdc.be.model.Component getAndValidateComponentForCreate(final String userId,
173                                                                                   final String componentId,
174                                                                                   final ComponentTypeEnum componentType,
175                                                                                   final boolean shouldLockComp) {
176         final ComponentParametersView componentParametersView = getBaseComponentParametersView();
177         final org.openecomp.sdc.be.model.Component component = validateComponentExists(componentId, componentType, componentParametersView);
178         if (shouldLockComp) {
179             // lock the component
180             lockComponent(component, CREATE_OUTPUT);
181         }
182         validateCanWorkOnComponent(component, userId);
183         return component;
184     }
185
186     private Either<List<OutputDefinition>, StorageOperationStatus> prepareOutputsForCreation(final String userId,
187                                                                                              final String cmptId,
188                                                                                              final List<OutputDefinition> outputsToCreate) {
189         final Map<String, OutputDefinition> outputsToPersist = MapUtil.toMap(outputsToCreate, OutputDefinition::getName);
190         assignOwnerIdToOutputs(userId, outputsToPersist);
191
192         return toscaOperationFacade.addOutputsToComponent(outputsToPersist, cmptId)
193             .left()
194             .map(persistedOutputs -> outputsToCreate);
195     }
196
197     private void assignOwnerIdToOutputs(final String userId, final Map<String, OutputDefinition> outputsToCreate) {
198         outputsToCreate.values().forEach(outputDefinition -> outputDefinition.setOwnerId(userId));
199     }
200
201     private ComponentParametersView getBaseComponentParametersView() {
202         final ComponentParametersView componentParametersView = new ComponentParametersView();
203         componentParametersView.disableAll();
204         componentParametersView.setIgnoreOutputs(false);
205         componentParametersView.setIgnoreAttributes(false);
206         componentParametersView.setIgnoreComponentInstances(false);
207         componentParametersView.setIgnoreComponentInstancesOutputs(false);
208         componentParametersView.setIgnoreComponentInstancesAttributes(false);
209         componentParametersView.setIgnoreUsers(false);
210         return componentParametersView;
211     }
212
213     /**
214      * Delete output from component
215      *
216      * @param componentId
217      * @param userId
218      * @param outputId
219      * @return
220      */
221     public OutputDefinition deleteOutput(final String componentId, final String userId, final String outputId) {
222
223         Either<OutputDefinition, ResponseFormat> deleteEither = null;
224         if (log.isDebugEnabled()) {
225             log.debug("Going to delete output id: {}", outputId);
226         }
227
228         validateUserExists(userId);
229
230         final ComponentParametersView componentParametersView = getBaseComponentParametersView();
231         componentParametersView.setIgnoreAttributes(false);
232
233         final Either<org.openecomp.sdc.be.model.Component, StorageOperationStatus> componentEither =
234             toscaOperationFacade.getToscaElement(componentId, componentParametersView);
235         if (componentEither.isRight()) {
236             throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(componentEither.right().value()));
237         }
238         final org.openecomp.sdc.be.model.Component component = componentEither.left().value();
239
240         // Validate outputId is child of the component
241         final Optional<OutputDefinition> optionalOutput = component.getOutputs().stream().
242             // filter by ID
243                 filter(output -> output.getUniqueId().equals(outputId)).
244             // Get the output
245                 findAny();
246         if (!optionalOutput.isPresent()) {
247             throw new ByActionStatusComponentException(ActionStatus.OUTPUT_IS_NOT_CHILD_OF_COMPONENT, outputId, componentId);
248         }
249
250         final OutputDefinition outputForDelete = optionalOutput.get();
251
252         // Lock component
253         lockComponent(componentId, component, "deleteOutput");
254         // Delete output operations
255         boolean failed = false;
256         try {
257             final StorageOperationStatus status =
258                 toscaOperationFacade.deleteOutputOfResource(component, outputForDelete.getName());
259             if (status != StorageOperationStatus.OK) {
260                 log.debug("Component id: {} delete output id: {} failed", componentId, outputId);
261                 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(status), component.getName());
262             }
263
264             final StorageOperationStatus storageOperationStatus =
265                 attributeDeclarationOrchestrator.unDeclareAttributesAsOutputs(component, outputForDelete);
266             if (storageOperationStatus != StorageOperationStatus.OK) {
267                 log.debug("Component id: {} update attributes declared as output for outputId: {} failed", componentId, outputId);
268                 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(storageOperationStatus), component.getName());
269             }
270             return outputForDelete;
271         } catch (final ComponentException e) {
272             failed = true;
273             throw e;
274         } finally {
275             unlockComponent(failed, component);
276         }
277     }
278
279 }