Support TOSCA functions in Node Filters
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / ComponentNodeFilterBusinessLogic.java
1 /*
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2020 Nordix Foundation
4  *  ================================================================================
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  *
16  *  SPDX-License-Identifier: Apache-2.0
17  *  ============LICENSE_END=========================================================
18  */
19 package org.openecomp.sdc.be.components.impl;
20
21 import static org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR;
22
23 import fj.data.Either;
24 import java.util.Arrays;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Map.Entry;
28 import java.util.Optional;
29 import org.openecomp.sdc.be.components.impl.exceptions.BusinessLogicException;
30 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
31 import org.openecomp.sdc.be.components.impl.utils.CINodeFilterUtils;
32 import org.openecomp.sdc.be.components.validation.NodeFilterValidator;
33 import org.openecomp.sdc.be.dao.api.ActionStatus;
34 import org.openecomp.sdc.be.datatypes.elements.CINodeFilterDataDefinition;
35 import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
36 import org.openecomp.sdc.be.datatypes.elements.PropertyFilterDataDefinition;
37 import org.openecomp.sdc.be.datatypes.elements.RequirementNodeFilterCapabilityDataDefinition;
38 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
39 import org.openecomp.sdc.be.datatypes.enums.NodeFilterConstraintType;
40 import org.openecomp.sdc.be.model.Component;
41 import org.openecomp.sdc.be.model.ComponentInstance;
42 import org.openecomp.sdc.be.model.UploadNodeFilterInfo;
43 import org.openecomp.sdc.be.model.User;
44 import org.openecomp.sdc.be.model.dto.FilterConstraintDto;
45 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
46 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
47 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.NodeFilterOperation;
48 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
49 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
50 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
51 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
52 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
53 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
54 import org.openecomp.sdc.be.ui.mapper.FilterConstraintMapper;
55 import org.openecomp.sdc.be.ui.model.UIConstraint;
56 import org.openecomp.sdc.be.user.Role;
57 import org.openecomp.sdc.common.log.wrappers.Logger;
58 import org.openecomp.sdc.exception.ResponseFormat;
59 import org.springframework.beans.factory.annotation.Autowired;
60
61 @org.springframework.stereotype.Component("componentNodeFilterBusinessLogic")
62 public class ComponentNodeFilterBusinessLogic extends BaseBusinessLogic {
63
64     private static final Logger LOGGER = Logger.getLogger(ComponentNodeFilterBusinessLogic.class.getName());
65     private final NodeFilterOperation nodeFilterOperation;
66     private final NodeFilterValidator nodeFilterValidator;
67
68     @Autowired
69     public ComponentNodeFilterBusinessLogic(final IElementOperation elementDao, final IGroupOperation groupOperation,
70                                             final IGroupInstanceOperation groupInstanceOperation, final IGroupTypeOperation groupTypeOperation,
71                                             final InterfaceOperation interfaceOperation,
72                                             final InterfaceLifecycleOperation interfaceLifecycleTypeOperation,
73                                             final ArtifactsOperations artifactToscaOperation, final NodeFilterOperation nodeFilterOperation,
74                                             final NodeFilterValidator nodeFilterValidator) {
75         super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation,
76             artifactToscaOperation);
77         this.nodeFilterOperation = nodeFilterOperation;
78         this.nodeFilterValidator = nodeFilterValidator;
79     }
80
81     public Optional<CINodeFilterDataDefinition> createNodeFilterIfNotExist(final String componentId, final String componentInstanceId,
82                                                                            final boolean shouldLock, final ComponentTypeEnum componentTypeEnum)
83         throws BusinessLogicException {
84         final Component component = getComponent(componentId);
85         Optional<CINodeFilterDataDefinition> filterDataDefinition = 
86             component.getComponentInstanceById(componentInstanceId).map(ComponentInstance::getNodeFilter);
87         if (filterDataDefinition.isPresent()) {
88             return filterDataDefinition;
89         }
90         final Either<CINodeFilterDataDefinition, StorageOperationStatus> result;
91         boolean wasLocked = false;
92         try {
93             if (shouldLock) {
94                 lockComponent(component.getUniqueId(), component, "Create Node Filter on component");
95                 wasLocked = true;
96             }
97             result = nodeFilterOperation.createNodeFilter(componentId, componentInstanceId);
98             if (result.isRight()) {
99                 janusGraphDao.rollback();
100                 LOGGER.error(BUSINESS_PROCESS_ERROR, "Failed to Create Node filter on component with id {}", componentId);
101                 throw new BusinessLogicException(componentsUtils
102                     .getResponseFormatByResource(componentsUtils.convertFromStorageResponse(result.right().value()), component.getSystemName()));
103             } else {
104                 filterDataDefinition = Optional.ofNullable(result.left().value());
105             }
106             janusGraphDao.commit();
107             LOGGER.debug("Node filter successfully created in component {} . ", component.getSystemName());
108         } catch (final Exception e) {
109             janusGraphDao.rollback();
110             LOGGER.error(BUSINESS_PROCESS_ERROR, "Exception occurred during add Component node filter property values: {}", e.getMessage(), e);
111             throw new BusinessLogicException(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
112         } finally {
113             if (wasLocked) {
114                 unlockComponent(component.getUniqueId(), componentTypeEnum);
115             }
116         }
117         return filterDataDefinition;
118     }
119
120     public Optional<String> deleteNodeFilterIfExists(final String componentId, final String componentInstanceId, final boolean shouldLock,
121                                                      final ComponentTypeEnum componentTypeEnum) throws BusinessLogicException {
122         final Component component = getComponent(componentId);
123         final Optional<CINodeFilterDataDefinition> nodeFilterDataDefinition = getComponentInstanceNodeFilter(componentInstanceId, component);
124         if (nodeFilterDataDefinition.isEmpty()) {
125             return Optional.ofNullable(componentInstanceId);
126         }
127         final Either<String, StorageOperationStatus> result;
128         boolean wasLocked = false;
129         try {
130             if (shouldLock) {
131                 lockComponent(component.getUniqueId(), component, "Delete Node Filter from component");
132                 wasLocked = true;
133             }
134             result = nodeFilterOperation.deleteNodeFilter(component, componentInstanceId);
135             if (result.isRight()) {
136                 LOGGER.error(BUSINESS_PROCESS_ERROR, "Failed to delete node filter in component {}. Response is {}. ", component.getName(),
137                     result.right().value());
138                 janusGraphDao.rollback();
139                 throw new BusinessLogicException(componentsUtils
140                     .getResponseFormatByResource(componentsUtils.convertFromStorageResponse(result.right().value()), component.getSystemName()));
141             }
142             janusGraphDao.commit();
143             LOGGER.debug("Node filter successfully deleted in component {} . ", component.getSystemName());
144         } catch (final Exception e) {
145             LOGGER.error(BUSINESS_PROCESS_ERROR, "Exception occurred during delete deleting node filter: {}", e.getMessage(), e);
146             janusGraphDao.rollback();
147             throw new BusinessLogicException(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
148         } finally {
149             if (wasLocked) {
150                 unlockComponent(component.getUniqueId(), componentTypeEnum);
151             }
152         }
153         return Optional.ofNullable(result.left().value());
154     }
155
156     public Optional<CINodeFilterDataDefinition> addNodeFilter(final String componentId, final String componentInstanceId,
157                                                               final FilterConstraintDto filterConstraint, final boolean shouldLock,
158                                                               final ComponentTypeEnum componentTypeEnum,
159                                                               final NodeFilterConstraintType nodeFilterConstraintType,
160                                                               final String capabilityName) throws BusinessLogicException {
161         final Component component = getComponent(componentId);
162         validateNodeFilter(component, componentInstanceId, filterConstraint);
163         CINodeFilterDataDefinition nodeFilterDataDefinition = getComponentInstanceNodeFilterOrThrow(componentInstanceId, component);
164         boolean wasLocked = false;
165         try {
166             if (shouldLock) {
167                 lockComponent(component.getUniqueId(), component, "Add Node Filter on Component");
168                 wasLocked = true;
169             }
170             final PropertyFilterDataDefinition filterPropertyDataDefinition = new PropertyFilterDataDefinition();
171             filterPropertyDataDefinition.setName(filterConstraint.getPropertyName());
172             filterPropertyDataDefinition.setConstraints(List.of(new FilterConstraintMapper().mapTo(filterConstraint)));
173             final Either<CINodeFilterDataDefinition, StorageOperationStatus> result = addNodeFilter(componentId, componentInstanceId,
174                 nodeFilterConstraintType, nodeFilterDataDefinition, filterPropertyDataDefinition, capabilityName);
175             if (result.isRight()) {
176                 throw new BusinessLogicException(componentsUtils.getResponseFormatByResource(
177                     componentsUtils.convertFromStorageResponse(result.right().value()), component.getSystemName()
178                 ));
179             } else {
180                 nodeFilterDataDefinition = result.left().value();
181             }
182             janusGraphDao.commit();
183             LOGGER.debug("Node filter successfully created in component {} . ", component.getSystemName());
184         } catch (final Exception e) {
185             janusGraphDao.rollback();
186             LOGGER.error(BUSINESS_PROCESS_ERROR, "Exception occurred during add component node filter property values: {}", e.getMessage(), e);
187             if (e instanceof BusinessLogicException) {
188                 throw e;
189             }
190             throw new BusinessLogicException(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
191         } finally {
192             if (wasLocked) {
193                 unlockComponent(component.getUniqueId(), componentTypeEnum);
194             }
195         }
196         return Optional.ofNullable(nodeFilterDataDefinition);
197     }
198
199     public Optional<CINodeFilterDataDefinition> deleteNodeFilter(final String componentId, final String componentInstanceId, final int position,
200                                                                  final boolean shouldLock, final ComponentTypeEnum componentTypeEnum,
201                                                                  final NodeFilterConstraintType nodeFilterConstraintType)
202         throws BusinessLogicException {
203
204         final Component component = getComponent(componentId);
205         CINodeFilterDataDefinition nodeFilterDataDefinition = getComponentInstanceNodeFilterOrThrow(componentInstanceId, component);
206         boolean wasLocked = false;
207         try {
208             if (shouldLock) {
209                 lockComponent(component.getUniqueId(), component, "Add Node Filter on Component");
210                 wasLocked = true;
211             }
212             final Either<CINodeFilterDataDefinition, StorageOperationStatus> result = nodeFilterOperation
213                 .deleteConstraint(componentId, componentInstanceId, nodeFilterDataDefinition, position, nodeFilterConstraintType);
214             if (result.isRight()) {
215                 janusGraphDao.rollback();
216                 throw new BusinessLogicException(componentsUtils
217                     .getResponseFormatByResource(componentsUtils.convertFromStorageResponse(result.right().value()), component.getSystemName()));
218             } else {
219                 nodeFilterDataDefinition = result.left().value();
220             }
221             janusGraphDao.commit();
222             LOGGER.debug("Node filter successfully deleted in component {} . ", component.getSystemName());
223         } catch (final Exception e) {
224             janusGraphDao.rollback();
225             LOGGER.error(BUSINESS_PROCESS_ERROR, "Exception occurred during delete component node filter property values: {}", e.getMessage(), e);
226             throw new BusinessLogicException(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
227         } finally {
228             if (wasLocked) {
229                 unlockComponent(component.getUniqueId(), componentTypeEnum);
230             }
231         }
232         return Optional.ofNullable(nodeFilterDataDefinition);
233     }
234
235     private Either<CINodeFilterDataDefinition, StorageOperationStatus> addNodeFilter(final String componentId, final String componentInstanceId,
236                                                                                      final NodeFilterConstraintType nodeFilterConstraintType,
237                                                                                      final CINodeFilterDataDefinition nodeFilterDataDefinition,
238                                                                                      final PropertyFilterDataDefinition propertyFilterDataDefinition,
239                                                                                      final String capabilityName) {
240         if (NodeFilterConstraintType.PROPERTIES.equals(nodeFilterConstraintType)) {
241             return nodeFilterOperation
242                 .addPropertyFilter(componentId, componentInstanceId, nodeFilterDataDefinition, propertyFilterDataDefinition);
243         }
244         final RequirementNodeFilterCapabilityDataDefinition requirementNodeFilterCapabilityDataDefinition = new RequirementNodeFilterCapabilityDataDefinition();
245         requirementNodeFilterCapabilityDataDefinition.setName(capabilityName);
246         final ListDataDefinition<PropertyFilterDataDefinition> propertyDataDefinitionListDataDefinition = new ListDataDefinition<>();
247         propertyDataDefinitionListDataDefinition.getListToscaDataDefinition()
248             .add(propertyFilterDataDefinition);
249         requirementNodeFilterCapabilityDataDefinition.setProperties(propertyDataDefinitionListDataDefinition);
250         return nodeFilterOperation
251             .addCapabilities(componentId, componentInstanceId, nodeFilterDataDefinition, requirementNodeFilterCapabilityDataDefinition);
252     }
253
254     private void unlockComponent(final String componentUniqueId, final ComponentTypeEnum componentType) {
255         graphLockOperation.unlockComponent(componentUniqueId, componentType.getNodeType());
256     }
257
258     public User validateUser(final String userId) {
259         final User user = userValidations.validateUserExists(userId);
260         userValidations.validateUserRole(user, Arrays.asList(Role.DESIGNER, Role.ADMIN));
261         return user;
262     }
263
264     private Optional<ComponentInstance> getComponentInstance(final String componentInstanceId, final Component component) {
265         return component.getComponentInstanceById(componentInstanceId);
266     }
267
268     private Optional<CINodeFilterDataDefinition> getComponentInstanceNodeFilter(final String componentInstanceId, final Component component)
269         throws BusinessLogicException {
270         final Either<Boolean, ResponseFormat> response = nodeFilterValidator.validateComponentInstanceExist(component, componentInstanceId);
271         if (response.isRight()) {
272             throw new BusinessLogicException(
273                 componentsUtils.getResponseFormat(ActionStatus.NODE_FILTER_NOT_FOUND, response.right().value().getFormattedMessage()));
274         }
275         return getComponentInstance(componentInstanceId, component).map(ComponentInstance::getNodeFilter);
276     }
277
278     private CINodeFilterDataDefinition getComponentInstanceNodeFilterOrThrow(final String componentInstanceId,
279                                                                              final Component component) throws BusinessLogicException {
280         return getComponentInstanceNodeFilter(componentInstanceId, component).orElseThrow(
281             () -> new BusinessLogicException(componentsUtils.getResponseFormat(ActionStatus.NODE_FILTER_NOT_FOUND)));
282     }
283
284     private void validateNodeFilter(final Component component, final String componentInstanceId,
285                                     final FilterConstraintDto constraint) throws BusinessLogicException {
286         final Either<Boolean, ResponseFormat> response = nodeFilterValidator.validateFilter(component, componentInstanceId, constraint);
287         if (response.isRight()) {
288             throw new BusinessLogicException(response.right().value());
289         }
290     }
291
292     public Optional<CINodeFilterDataDefinition> updateNodeFilter(final String componentId, final String componentInstanceId,
293                                                                  final UIConstraint uiConstraint, final ComponentTypeEnum componentTypeEnum,
294                                                                  final NodeFilterConstraintType nodeFilterConstraintType,
295                                                                  final int index) throws BusinessLogicException {
296         final Optional<CINodeFilterDataDefinition> deleteActionResponse =
297             deleteNodeFilter(componentId, componentInstanceId, index, true, componentTypeEnum, nodeFilterConstraintType);
298         if (deleteActionResponse.isEmpty()) {
299             throw new BusinessLogicException(
300                 componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR, "Failed to delete node filter capabilities"));
301         }
302         return addNodeFilter(componentId.toLowerCase(), componentInstanceId, new FilterConstraintMapper().mapFrom(uiConstraint), true,
303             componentTypeEnum, nodeFilterConstraintType, uiConstraint.getCapabilityName());
304     }
305
306     public StorageOperationStatus associateNodeFilterToComponentInstance(final String componentId,
307                                                                          final Map<String, UploadNodeFilterInfo> instNodeFilter) {
308         for (Entry<String, UploadNodeFilterInfo> filter : instNodeFilter.entrySet()) {
309             String componentInstanceId = filter.getKey();
310             CINodeFilterDataDefinition ciNodeFilterDataDefinition = new CINodeFilterUtils()
311                 .getNodeFilterDataDefinition(filter.getValue(), componentInstanceId);
312             Either<CINodeFilterDataDefinition, StorageOperationStatus> nodeFilter = nodeFilterOperation.createNodeFilter(componentId,
313                 componentInstanceId);
314             if (nodeFilter.isRight()) {
315                 LOGGER.error(BUSINESS_PROCESS_ERROR, "Failed to Create Node filter on component instance with id {}",
316                     filter.getKey());
317                 return nodeFilter.right().value();
318             }
319
320             //associate node filter properties to component instance
321             List<PropertyFilterDataDefinition> properties = ciNodeFilterDataDefinition.getProperties()
322                 .getListToscaDataDefinition();
323             if (!properties.isEmpty()) {
324                 properties.forEach(property -> {
325                     Either<CINodeFilterDataDefinition, StorageOperationStatus> nodeFilterProperty = nodeFilterOperation
326                         .addPropertyFilter(componentId, componentInstanceId, nodeFilter.left().value(), property);
327                     if (nodeFilterProperty.isRight()) {
328                         throw new ComponentException(
329                             componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(nodeFilterProperty.right().value()),
330                                 componentInstanceId));
331                     }
332                 });
333             }
334
335             //associate node filter capabilities to component instance
336             List<RequirementNodeFilterCapabilityDataDefinition> capabilities = ciNodeFilterDataDefinition.getCapabilities()
337                 .getListToscaDataDefinition();
338             if (!capabilities.isEmpty()) {
339                 capabilities.forEach(capability -> {
340                     RequirementNodeFilterCapabilityDataDefinition requirementNodeFilterCapabilityDataDefinition =
341                         new RequirementNodeFilterCapabilityDataDefinition();
342                     requirementNodeFilterCapabilityDataDefinition.setName(capability.getName());
343                     requirementNodeFilterCapabilityDataDefinition.setProperties(getProperties(capability.getProperties()));
344                     Either<CINodeFilterDataDefinition, StorageOperationStatus> nodeFilterCapability = nodeFilterOperation
345                         .addCapabilities(componentId, componentInstanceId, nodeFilter.left().value(),
346                             requirementNodeFilterCapabilityDataDefinition);
347                     if (nodeFilterCapability.isRight()) {
348                         throw new ComponentException(
349                             componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(nodeFilterCapability.right().value()),
350                                 componentInstanceId));
351                     }
352                 });
353             }
354         }
355         return StorageOperationStatus.OK;
356     }
357
358     private ListDataDefinition<PropertyFilterDataDefinition> getProperties(ListDataDefinition<PropertyFilterDataDefinition> properties) {
359         ListDataDefinition<PropertyFilterDataDefinition> updatedProperties = new ListDataDefinition<>();
360         properties.getListToscaDataDefinition().forEach(updatedProperties::add);
361         return updatedProperties;
362     }
363
364 }