Maintain VFC UI added interface operations after an upgrade
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / ComponentInterfaceOperationBusinessLogic.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  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.zone-instance.component.ts
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  *
18  *  SPDX-License-Identifier: Apache-2.0
19  *  ============LICENSE_END=========================================================
20  */
21 package org.openecomp.sdc.be.components.impl;
22
23 import fj.data.Either;
24 import java.util.Arrays;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Optional;
29 import java.util.UUID;
30 import org.apache.commons.collections.CollectionUtils;
31 import org.apache.commons.collections.MapUtils;
32 import org.openecomp.sdc.be.components.impl.exceptions.BusinessLogicException;
33 import org.openecomp.sdc.be.components.validation.ComponentValidations;
34 import org.openecomp.sdc.be.dao.api.ActionStatus;
35 import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition;
36 import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
37 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
38 import org.openecomp.sdc.be.model.Component;
39 import org.openecomp.sdc.be.model.ComponentInstance;
40 import org.openecomp.sdc.be.model.ComponentInstanceInterface;
41 import org.openecomp.sdc.be.model.ComponentParametersView;
42 import org.openecomp.sdc.be.model.InterfaceDefinition;
43 import org.openecomp.sdc.be.model.User;
44 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
45 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
46 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
47 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
48 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
49 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
50 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
51 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
52 import org.openecomp.sdc.be.user.Role;
53 import org.openecomp.sdc.common.datastructure.Wrapper;
54 import org.openecomp.sdc.exception.ResponseFormat;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57 import org.springframework.beans.factory.annotation.Autowired;
58
59 @org.springframework.stereotype.Component("componentInterfaceOperationBusinessLogic")
60 public class ComponentInterfaceOperationBusinessLogic extends BaseBusinessLogic {
61
62     private static final Logger LOGGER = LoggerFactory.getLogger(ComponentInterfaceOperationBusinessLogic.class);
63     private final ComponentValidations componentValidations;
64
65     @Autowired
66     public ComponentInterfaceOperationBusinessLogic(final IElementOperation elementDao, final IGroupOperation groupOperation,
67                                                     final IGroupInstanceOperation groupInstanceOperation,
68                                                     final IGroupTypeOperation groupTypeOperation, final InterfaceOperation interfaceOperation,
69                                                     final InterfaceLifecycleOperation interfaceLifecycleTypeOperation,
70                                                     final ArtifactsOperations artifactToscaOperation,
71                                                     final ComponentValidations componentValidations) {
72         super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation,
73             artifactToscaOperation);
74         this.componentValidations = componentValidations;
75     }
76
77     public Optional<ComponentInstance> updateComponentInstanceInterfaceOperation(final String componentId, final String componentInstanceId,
78                                                                                  final InterfaceDefinition interfaceDefinition,
79                                                                                  final ComponentTypeEnum componentTypeEnum,
80                                                                                  final Wrapper<ResponseFormat> errorWrapper, final boolean shouldLock)
81         throws BusinessLogicException {
82         final Component component = getComponent(componentId);
83         final Optional<ComponentInstance> componentInstanceOptional = componentValidations.getComponentInstance(component, componentInstanceId);
84         ResponseFormat responseFormat;
85         if (componentInstanceOptional.isEmpty()) {
86             responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND);
87             LOGGER.debug("Failed to found component instance with id {}, error: {}", componentInstanceId, responseFormat);
88             errorWrapper.setInnerElement(responseFormat);
89             return Optional.empty();
90         }
91         Map<String, List<ComponentInstanceInterface>> componentInstancesInterfaceMap = component.getComponentInstancesInterfaces();
92         if (MapUtils.isEmpty(componentInstancesInterfaceMap)) {
93             componentInstancesInterfaceMap = new HashMap<>();
94             component.setComponentInstancesInterfaces(componentInstancesInterfaceMap);
95         }
96         final List<ComponentInstanceInterface> componentInstanceInterfaceList = componentInstancesInterfaceMap.get(componentInstanceId);
97         if (CollectionUtils.isEmpty(componentInstanceInterfaceList)) {
98             responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND);
99             LOGGER.debug("Failed to found component instance with id {}, error: {}", componentInstanceId, responseFormat);
100             errorWrapper.setInnerElement(responseFormat);
101             return Optional.empty();
102         }
103         final Optional<OperationDataDefinition> optionalOperationDataDefinition = interfaceDefinition.getOperations().values().stream().findFirst();
104         if (optionalOperationDataDefinition.isEmpty()) {
105             responseFormat = componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND);
106             LOGGER.debug("Failed to found interface operation on component instance with id {}, error: {}", componentInstanceId, responseFormat);
107             errorWrapper.setInnerElement(responseFormat);
108             return Optional.empty();
109         }
110         final OperationDataDefinition updatedOperationDataDefinition = optionalOperationDataDefinition.get();
111         final Optional<ComponentInstanceInterface> optionalComponentInstanceInterface = componentInstanceInterfaceList.stream().filter(
112                 ci -> ci.getOperations().values().stream().anyMatch(
113                     operationDataDefinition -> operationDataDefinition.getUniqueId().equalsIgnoreCase(updatedOperationDataDefinition.getUniqueId())))
114             .findFirst();
115         if (optionalComponentInstanceInterface.isEmpty()) {
116             responseFormat = componentsUtils.getResponseFormat(ActionStatus.INTERFACE_NOT_FOUND_IN_COMPONENT);
117             LOGGER
118                 .debug("Failed to found ComponentInstanceInterface on component instance with id {}, error: {}", componentInstanceId, responseFormat);
119             errorWrapper.setInnerElement(responseFormat);
120             return Optional.empty();
121         }
122         updateOperationDefinitionImplementation(updatedOperationDataDefinition);
123         optionalComponentInstanceInterface.get().getOperations().replace(updatedOperationDataDefinition.getName(), updatedOperationDataDefinition);
124         boolean wasLocked = false;
125         try {
126             if (shouldLock) {
127                 lockComponent(componentId, component, "Update Interface Operation on Component instance");
128                 wasLocked = true;
129             }
130             final StorageOperationStatus status = toscaOperationFacade.updateComponentInstanceInterfaces(component, componentInstanceId);
131             if (status != StorageOperationStatus.OK) {
132                 janusGraphDao.rollback();
133                 responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR);
134                 LOGGER.error("Exception occurred when updating Component Instance Interfaces {}", responseFormat);
135                 errorWrapper.setInnerElement(responseFormat);
136                 return Optional.empty();
137             }
138             final ComponentParametersView componentFilter = new ComponentParametersView();
139             componentFilter.disableAll();
140             componentFilter.setIgnoreUsers(false);
141             componentFilter.setIgnoreComponentInstances(false);
142             componentFilter.setIgnoreInterfaces(false);
143             componentFilter.setIgnoreComponentInstancesInterfaces(false);
144             final Either<Component, StorageOperationStatus> operationStatusEither = toscaOperationFacade
145                 .updateComponentInstanceMetadataOfTopologyTemplate(component, componentFilter);
146             if (operationStatusEither.isRight()) {
147                 janusGraphDao.rollback();
148                 responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR);
149                 LOGGER.error("Exception occurred when updating Component Instance Topology template {}", responseFormat);
150                 errorWrapper.setInnerElement(responseFormat);
151                 return Optional.empty();
152             }
153             janusGraphDao.commit();
154         } catch (final Exception e) {
155             janusGraphDao.rollback();
156             LOGGER.error("Exception occurred when updating Interface Operation on Component Instance: {}", e.getMessage(), e);
157             responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR);
158             errorWrapper.setInnerElement(responseFormat);
159             throw new BusinessLogicException(responseFormat);
160         } finally {
161             if (wasLocked) {
162                 unlockComponent(component.getUniqueId(), componentTypeEnum);
163             }
164         }
165         return componentInstanceOptional;
166     }
167
168     public Optional<Component> updateResourceInterfaceOperation(final String componentId,
169                                                                 final InterfaceDefinition interfaceDefinition,
170                                                                 final ComponentTypeEnum componentTypeEnum,
171                                                                 final Wrapper<ResponseFormat> errorWrapper,
172                                                                 final boolean shouldLock) throws BusinessLogicException {
173         final var component = getComponent(componentId);
174         ResponseFormat responseFormat;
175
176         Map<String, InterfaceDefinition> componentInterfaceMap = component.getInterfaces();
177         final String interfaceDefinitionType = interfaceDefinition.getType();
178         if (MapUtils.isEmpty(componentInterfaceMap)) {
179             componentInterfaceMap = new HashMap<>();
180             componentInterfaceMap.put(interfaceDefinitionType, interfaceDefinition);
181             component.setInterfaces(componentInterfaceMap);
182         } else {
183             InterfaceDefinition componentInterfaceDefinition = componentInterfaceMap.get(interfaceDefinitionType);
184             if (componentInterfaceDefinition == null) {
185                 componentInterfaceDefinition = interfaceDefinition;
186                 componentInterfaceMap.put(interfaceDefinitionType, interfaceDefinition);
187             }
188
189             final Map<String, OperationDataDefinition> interfaceDefinitionOperations = interfaceDefinition.getOperations();
190             final Optional<OperationDataDefinition> optionalOperationDataDefinition = interfaceDefinitionOperations.values().stream().findFirst();
191             if (optionalOperationDataDefinition.isEmpty()) {
192                 responseFormat = componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND);
193                 LOGGER.debug("Failed to found interface operation on provided InterfaceDefinition {}, error: {}",
194                     interfaceDefinitionType, responseFormat);
195                 errorWrapper.setInnerElement(responseFormat);
196                 return Optional.empty();
197             }
198             final var updatedOperationDataDefinition = optionalOperationDataDefinition.get();
199             updateOperationDefinitionImplementation(updatedOperationDataDefinition);
200             Map<String, OperationDataDefinition> componentOperationDataDefinitionMap = componentInterfaceDefinition.getOperations();
201             if (MapUtils.isEmpty(componentOperationDataDefinitionMap)) {
202                 componentOperationDataDefinitionMap = new HashMap<>();
203                 componentInterfaceDefinition.setOperations(componentOperationDataDefinitionMap);
204             }
205             componentOperationDataDefinitionMap.replace(updatedOperationDataDefinition.getName(), updatedOperationDataDefinition);
206         }
207         boolean wasLocked = false;
208         try {
209             if (shouldLock) {
210                 lockComponent(componentId, component, "Update Interface Operation on Component instance");
211                 wasLocked = true;
212             }
213             final StorageOperationStatus status = toscaOperationFacade.updateComponentInterfaces(component, interfaceDefinitionType);
214             if (status != StorageOperationStatus.OK) {
215                 janusGraphDao.rollback();
216                 responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR);
217                 LOGGER.error("Exception occurred when updating Component Instance Interfaces {}", responseFormat);
218                 errorWrapper.setInnerElement(responseFormat);
219                 return Optional.empty();
220             }
221             janusGraphDao.commit();
222         } catch (final Exception e) {
223             janusGraphDao.rollback();
224             LOGGER.error("Exception occurred when updating Interface Operation on Component Instance: ", e);
225             responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR);
226             errorWrapper.setInnerElement(responseFormat);
227             throw new BusinessLogicException(responseFormat);
228         } finally {
229             if (wasLocked) {
230                 unlockComponent(component.getUniqueId(), componentTypeEnum);
231             }
232         }
233         return Optional.of(component);
234     }
235
236     public Optional<Component> createInterfaceOperationInResource(final String componentId, final InterfaceDefinition interfaceDefinition,
237                                                                   final ComponentTypeEnum componentTypeEnum,
238                                                                   final Wrapper<ResponseFormat> errorWrapper, final boolean shouldLock)
239         throws BusinessLogicException {
240         final Component component = getComponent(componentId);
241         ResponseFormat responseFormat;
242         final String componentInterfaceUpdatedKey = interfaceDefinition.getType();
243
244         Map<String, InterfaceDefinition> componentInterfaceMap = component.getInterfaces();
245         if (MapUtils.isEmpty(componentInterfaceMap)) {
246             componentInterfaceMap = new HashMap<>();
247             component.setInterfaces(componentInterfaceMap);
248         }
249
250         interfaceDefinition.setUniqueId(componentInterfaceUpdatedKey);
251         interfaceDefinition.setToscaResourceName(componentInterfaceUpdatedKey);
252         interfaceDefinition.setUserCreated(true);
253
254         final Optional<OperationDataDefinition> optionalOperationDataDefinition = interfaceDefinition.getOperations().values().stream().findFirst();
255         if (optionalOperationDataDefinition.isEmpty()) {
256             responseFormat = componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND);
257             LOGGER.debug("Failed to found interface operation on component instance with id {}, error: {}", componentId, responseFormat);
258             errorWrapper.setInnerElement(responseFormat);
259             return Optional.empty();
260         }
261
262         final OperationDataDefinition updatedOperationDataDefinition = optionalOperationDataDefinition.get();
263         updatedOperationDataDefinition.setUniqueId(UUID.randomUUID().toString());
264
265         final InterfaceDefinition interfaceDefinitionFound = componentInterfaceMap.get(componentInterfaceUpdatedKey);
266         if (interfaceDefinitionFound != null) {
267             final Map<String, OperationDataDefinition> operationsFromComponent = interfaceDefinitionFound.getOperations();
268             final String updatedOperationDataDefinitionName = updatedOperationDataDefinition.getName();
269             final boolean find = operationsFromComponent.containsKey(updatedOperationDataDefinitionName);
270             if (find) {
271                 responseFormat = componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NAME_ALREADY_IN_USE,
272                     updatedOperationDataDefinitionName);
273                 LOGGER.error("Operation '{}' for Interface '{}' already exist, error: '{}'", updatedOperationDataDefinitionName,
274                     componentInterfaceUpdatedKey, responseFormat);
275                 errorWrapper.setInnerElement(responseFormat);
276                 return Optional.empty();
277             } else {
278                 operationsFromComponent.put(updatedOperationDataDefinitionName, updatedOperationDataDefinition);
279                 interfaceDefinition.setOperations(operationsFromComponent);
280             }
281         }
282
283         componentInterfaceMap.put(componentInterfaceUpdatedKey, interfaceDefinition);
284
285         boolean wasLocked = false;
286         try {
287             if (shouldLock) {
288                 lockComponent(componentId, component, "Update Interface Operation on Component instance");
289                 wasLocked = true;
290             }
291             final Either<InterfaceDefinition, StorageOperationStatus> operationStatusEither =
292                 toscaOperationFacade.addInterfaceToComponent(componentInterfaceUpdatedKey, interfaceDefinition, component);
293             if (operationStatusEither.isRight()) {
294                 janusGraphDao.rollback();
295                 responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR);
296                 LOGGER.error("Exception occurred when updating Component Instance Interfaces {}", responseFormat);
297                 errorWrapper.setInnerElement(responseFormat);
298                 return Optional.empty();
299             }
300             janusGraphDao.commit();
301         } catch (final Exception e) {
302             janusGraphDao.rollback();
303             LOGGER.error("Exception occurred when updating Interface Operation on Component Instance: ", e);
304             responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR);
305             errorWrapper.setInnerElement(responseFormat);
306             throw new BusinessLogicException(responseFormat);
307         } finally {
308             if (wasLocked) {
309                 unlockComponent(component.getUniqueId(), componentTypeEnum);
310             }
311         }
312         return Optional.of(component);
313     }
314
315     public User validateUser(final String userId) {
316         final User user = userValidations.validateUserExists(userId);
317         userValidations.validateUserRole(user, Arrays.asList(Role.DESIGNER, Role.ADMIN));
318         return user;
319     }
320
321     private void unlockComponent(final String componentUniqueId, final ComponentTypeEnum componentType) {
322         graphLockOperation.unlockComponent(componentUniqueId, componentType.getNodeType());
323     }
324
325     private void updateOperationDefinitionImplementation(final OperationDataDefinition updatedOperationDataDefinition) {
326         final ArtifactDataDefinition artifactInfo = new ArtifactDataDefinition(updatedOperationDataDefinition.getImplementation());
327         artifactInfo.setArtifactName(String.format("'%s'", updatedOperationDataDefinition.getImplementation().getArtifactName()));
328         updatedOperationDataDefinition.setImplementation(artifactInfo);
329     }
330 }