Implement adding Interface to VFC
[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
253         final Optional<OperationDataDefinition> optionalOperationDataDefinition = interfaceDefinition.getOperations().values().stream().findFirst();
254         if (optionalOperationDataDefinition.isEmpty()) {
255             responseFormat = componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND);
256             LOGGER.debug("Failed to found interface operation on component instance with id {}, error: {}", componentId, responseFormat);
257             errorWrapper.setInnerElement(responseFormat);
258             return Optional.empty();
259         }
260
261         final OperationDataDefinition updatedOperationDataDefinition = optionalOperationDataDefinition.get();
262         updatedOperationDataDefinition.setUniqueId(UUID.randomUUID().toString());
263
264         final InterfaceDefinition interfaceDefinitionFound = componentInterfaceMap.get(componentInterfaceUpdatedKey);
265         if (interfaceDefinitionFound != null) {
266             final Map<String, OperationDataDefinition> operationsFromComponent = interfaceDefinitionFound.getOperations();
267             final String updatedOperationDataDefinitionName = updatedOperationDataDefinition.getName();
268             final boolean find = operationsFromComponent.containsKey(updatedOperationDataDefinitionName);
269             if (find) {
270                 responseFormat = componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NAME_ALREADY_IN_USE,
271                     updatedOperationDataDefinitionName);
272                 LOGGER.error("Operation '{}' for Interface '{}' already exist, error: '{}'", updatedOperationDataDefinitionName,
273                     componentInterfaceUpdatedKey, responseFormat);
274                 errorWrapper.setInnerElement(responseFormat);
275                 return Optional.empty();
276             } else {
277                 operationsFromComponent.put(updatedOperationDataDefinitionName, updatedOperationDataDefinition);
278                 interfaceDefinition.setOperations(operationsFromComponent);
279             }
280         }
281
282         componentInterfaceMap.put(componentInterfaceUpdatedKey, interfaceDefinition);
283
284         boolean wasLocked = false;
285         try {
286             if (shouldLock) {
287                 lockComponent(componentId, component, "Update Interface Operation on Component instance");
288                 wasLocked = true;
289             }
290             final Either<InterfaceDefinition, StorageOperationStatus> operationStatusEither =
291                 toscaOperationFacade.addInterfaceToComponent(componentInterfaceUpdatedKey, interfaceDefinition, component);
292             if (operationStatusEither.isRight()) {
293                 janusGraphDao.rollback();
294                 responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR);
295                 LOGGER.error("Exception occurred when updating Component Instance Interfaces {}", responseFormat);
296                 errorWrapper.setInnerElement(responseFormat);
297                 return Optional.empty();
298             }
299             janusGraphDao.commit();
300         } catch (final Exception e) {
301             janusGraphDao.rollback();
302             LOGGER.error("Exception occurred when updating Interface Operation on Component Instance: ", e);
303             responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR);
304             errorWrapper.setInnerElement(responseFormat);
305             throw new BusinessLogicException(responseFormat);
306         } finally {
307             if (wasLocked) {
308                 unlockComponent(component.getUniqueId(), componentTypeEnum);
309             }
310         }
311         return Optional.of(component);
312     }
313
314     public User validateUser(final String userId) {
315         final User user = userValidations.validateUserExists(userId);
316         userValidations.validateUserRole(user, Arrays.asList(Role.DESIGNER, Role.ADMIN));
317         return user;
318     }
319
320     private void unlockComponent(final String componentUniqueId, final ComponentTypeEnum componentType) {
321         graphLockOperation.unlockComponent(componentUniqueId, componentType.getNodeType());
322     }
323
324     private void updateOperationDefinitionImplementation(final OperationDataDefinition updatedOperationDataDefinition) {
325         final ArtifactDataDefinition artifactInfo = new ArtifactDataDefinition(updatedOperationDataDefinition.getImplementation());
326         artifactInfo.setArtifactName(String.format("'%s'", updatedOperationDataDefinition.getImplementation().getArtifactName()));
327         updatedOperationDataDefinition.setImplementation(artifactInfo);
328     }
329 }