Upgrade SDC from Titan to Janus Graph
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / GroupBusinessLogicNew.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. 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  * Modifications copyright (c) 2019 Nokia
20  * ================================================================================
21  */
22 package org.openecomp.sdc.be.components.impl;
23
24 import org.apache.commons.collections.CollectionUtils;
25 import org.apache.commons.collections.MapUtils;
26 import org.apache.commons.lang.StringUtils;
27 import org.apache.commons.lang3.math.NumberUtils;
28 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
29 import org.openecomp.sdc.be.components.impl.lock.LockingTransactional;
30 import org.openecomp.sdc.be.components.validation.AccessValidations;
31 import org.openecomp.sdc.be.components.validation.ComponentValidations;
32 import org.openecomp.sdc.be.dao.api.ActionStatus;
33 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
34 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
35 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
36 import org.openecomp.sdc.be.model.*;
37 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.GroupsOperation;
38 import org.openecomp.sdc.be.model.operations.StorageException;
39 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
40 import org.openecomp.sdc.be.model.operations.impl.GroupOperation;
41 import org.openecomp.sdc.common.util.ValidationUtils;
42 import org.springframework.transaction.annotation.Transactional;
43
44 import java.util.*;
45 import java.util.stream.Collectors;
46
47 import static org.openecomp.sdc.be.components.impl.BaseBusinessLogic.enumHasValueFilter;
48
49 @org.springframework.stereotype.Component
50 public class GroupBusinessLogicNew {
51
52     private final AccessValidations accessValidations;
53     private final ComponentValidations componentValidations;
54     private final GroupsOperation groupsOperation;
55     private final GroupOperation groupOperation;
56
57     public GroupBusinessLogicNew(AccessValidations accessValidations, ComponentValidations componentValidations, GroupsOperation groupsOperation, GroupOperation groupOperation) {
58         this.accessValidations = accessValidations;
59         this.componentValidations = componentValidations;
60         this.groupsOperation = groupsOperation;
61         this.groupOperation = groupOperation;
62     }
63
64     @LockingTransactional
65     public List<String> updateMembers(String componentId, ComponentTypeEnum componentType, String userId, String groupUniqueId, List<String> members) {
66         Component component = accessValidations.validateUserCanWorkOnComponent(componentId, componentType, userId, "UPDATE GROUP MEMBERS");
67         GroupDefinition groupDefinition = getGroup(component, groupUniqueId);
68         groupDefinition.setMembers(buildMembersMap(component, members));
69         groupsOperation.updateGroupOnComponent(componentId, groupDefinition);
70         return new ArrayList<>(groupDefinition.getMembers().values());
71     }
72
73     @LockingTransactional
74     public List<GroupProperty> updateProperties(String componentId, ComponentTypeEnum componentType, String userId, String groupUniqueId, List<GroupProperty> newProperties) {
75         Component component = accessValidations.validateUserCanWorkOnComponent(componentId, componentType, userId, "UPDATE GROUP PROPERTIES");
76         GroupDefinition currentGroup = getGroup(component, groupUniqueId);
77         validateUpdatedPropertiesAndSetEmptyValues(currentGroup, newProperties);
78         return groupsOperation.updateGroupPropertiesOnComponent(componentId, currentGroup, newProperties)
79                 .left()
80                 .on(this::onUpdatePropertyError);
81     }
82
83     @Transactional
84     public List<PropertyDataDefinition> getProperties(String componentType, String userId, String componentId, String groupUniqueId) {
85         Component component = accessValidations.validateUserCanRetrieveComponentData(componentId, componentType, userId, "GET GROUP PROPERTIES");
86         GroupDefinition currentGroup = getGroup(component, groupUniqueId);
87         return currentGroup.getProperties();
88     }
89
90     private List<GroupProperty> onUpdatePropertyError(StorageOperationStatus storageOperationStatus) {
91         throw new StorageException(storageOperationStatus);
92     }
93
94     private Map<String, String> buildMembersMap(Component component, List<String> newMemberUniqueIds) {
95         Map<String, String> nameToUniqueId = new HashMap<>();
96         for (String memberUniqueId : newMemberUniqueIds) {
97             ComponentInstance componentInstance = getComponentInstance(component, memberUniqueId);
98             nameToUniqueId.put(componentInstance.getName(), componentInstance.getUniqueId());
99         }
100         return nameToUniqueId;
101     }
102
103     private ComponentInstance getComponentInstance(Component component, String memberUniqueId) {
104         return componentValidations.getComponentInstance(component, memberUniqueId)
105                 .orElseThrow(() -> new ByActionStatusComponentException(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND_ON_CONTAINER,
106                         memberUniqueId, "",
107                         component.getActualComponentType(), component.getSystemName()));
108     }
109
110     private GroupDefinition getGroup(Component component, String groupUniqueId) {
111         return component.getGroupById(groupUniqueId)
112                 .orElseThrow(() -> new ByActionStatusComponentException(ActionStatus.GROUP_IS_MISSING,
113                         component.getSystemName(), component.getActualComponentType()));
114     }
115
116     private void validateUpdatedPropertiesAndSetEmptyValues(GroupDefinition originalGroup, List<GroupProperty> groupPropertiesToUpdate) {
117
118         if (CollectionUtils.isEmpty(groupPropertiesToUpdate)) {
119             throw new ByActionStatusComponentException(ActionStatus.PROPERTY_NOT_FOUND, StringUtils.EMPTY);
120         }
121         if (CollectionUtils.isEmpty(originalGroup.getProperties())) {
122             throw new ByActionStatusComponentException(ActionStatus.PROPERTY_NOT_FOUND, groupPropertiesToUpdate.get(NumberUtils.INTEGER_ZERO).getName());
123         }
124         Map<String, GroupProperty> originalProperties = originalGroup.convertToGroupProperties()
125                 .stream()
126                 .collect(Collectors.toMap(PropertyDataDefinition::getName, p -> p));
127
128
129         for (GroupProperty gp : groupPropertiesToUpdate) {
130             String updatedPropertyName = gp.getName();
131             if (!originalProperties.containsKey(updatedPropertyName)) {
132                 throw new ByActionStatusComponentException(ActionStatus.PROPERTY_NOT_FOUND, updatedPropertyName);
133             }
134             if (!isOnlyGroupPropertyValueChanged(gp, originalProperties.get(updatedPropertyName))) {
135                 throw new ByActionStatusComponentException(ActionStatus.INVALID_PROPERTY, updatedPropertyName);
136             }
137             if (StringUtils.isEmpty(gp.getValue())) {
138                 gp.setValue(originalProperties.get(updatedPropertyName).getDefaultValue());
139             }
140             StorageOperationStatus sos = groupOperation.validateAndUpdatePropertyValue(gp);
141             if (StorageOperationStatus.OK != sos) {
142                 throw new StorageException(sos, updatedPropertyName);
143             }
144         }
145
146         validatePropertyBusinessLogic(groupPropertiesToUpdate, originalGroup);
147     }
148
149     private void validatePropertyBusinessLogic(List<GroupProperty> groupPropertiesToUpdate, GroupDefinition originalGroup) {
150
151         Map<PropertyDefinition.PropertyNames, String> enumValueMap = new EnumMap<>(PropertyDefinition.PropertyNames.class);
152         for (GroupProperty gp : groupPropertiesToUpdate) {
153             // Filter out non special properties which does not have Enum
154             final PropertyDefinition.PropertyNames gpEnum = PropertyDefinition.PropertyNames.findName(gp.getName());
155             if (gpEnum != null) {
156                 enumValueMap.put(gpEnum, gp.getValue());
157             }
158         }
159         if (MapUtils.isEmpty(enumValueMap)) {
160             return;
161         }
162
163         validateVFInstancesLogic(enumValueMap, prepareMapWithOriginalProperties(originalGroup));
164
165         if (enumValueMap.containsKey(PropertyDefinition.PropertyNames.VF_MODULE_DESCRIPTION) || enumValueMap.containsKey(PropertyDefinition.PropertyNames.VF_MODULE_LABEL)) {
166             groupPropertiesToUpdate.stream()
167                     .filter(e -> enumHasValueFilter(e.getName(), PropertyDefinition.PropertyNames::findName, PropertyDefinition.PropertyNames.VF_MODULE_DESCRIPTION, PropertyDefinition.PropertyNames.VF_MODULE_LABEL))
168                     .forEach(this::validateFreeText);
169         }
170     }
171
172     private Map<PropertyDefinition.PropertyNames, String> prepareMapWithOriginalProperties(GroupDefinition originalGroup) {
173         Map<PropertyDefinition.PropertyNames, String> oldValueMap = new EnumMap<>(PropertyDefinition.PropertyNames.class);
174         PropertyDefinition.PropertyNames[] propertiesToCheck = new PropertyDefinition.PropertyNames[] { PropertyDefinition.PropertyNames.INITIAL_COUNT, PropertyDefinition.PropertyNames.MAX_INSTANCES, PropertyDefinition.PropertyNames.MIN_INSTANCES };
175
176         for (GroupProperty gp : originalGroup.convertToGroupProperties()) {
177             if (enumHasValueFilter(gp.getName(), PropertyDefinition.PropertyNames::findName, propertiesToCheck)) {
178                 oldValueMap.put(PropertyDefinition.PropertyNames.findName(gp.getName()), gp.getValue());
179             }
180         }
181         if (StringUtils.isEmpty(oldValueMap.get(PropertyDefinition.PropertyNames.MAX_INSTANCES))) {
182             oldValueMap.put(PropertyDefinition.PropertyNames.MAX_INSTANCES, String.valueOf(Integer.MAX_VALUE));
183         }
184         return oldValueMap;
185     }
186
187     private void validateVFInstancesLogic(Map<PropertyDefinition.PropertyNames, String> newValues, Map<PropertyDefinition.PropertyNames, String> parentValues) {
188         if (!newValues.containsKey(PropertyDefinition.PropertyNames.INITIAL_COUNT)
189                 && !newValues.containsKey(PropertyDefinition.PropertyNames.MAX_INSTANCES)
190                 && !newValues.containsKey(PropertyDefinition.PropertyNames.MIN_INSTANCES)) {
191             return;
192         }
193         int latestMaxInstances = getLatestIntProperty(newValues, parentValues, PropertyDefinition.PropertyNames.MAX_INSTANCES);
194         int latestInitialCount = getLatestIntProperty(newValues, parentValues, PropertyDefinition.PropertyNames.INITIAL_COUNT);
195         int latestMinInstances = getLatestIntProperty(newValues, parentValues, PropertyDefinition.PropertyNames.MIN_INSTANCES);
196
197         if (isPropertyChanged(newValues, parentValues, PropertyDefinition.PropertyNames.INITIAL_COUNT)
198                 && (latestInitialCount > latestMaxInstances || latestInitialCount < latestMinInstances)) {
199             throw new ByActionStatusComponentException(ActionStatus.INVALID_GROUP_INITIAL_COUNT_PROPERTY_VALUE, PropertyDefinition.PropertyNames.INITIAL_COUNT.getPropertyName(), String.valueOf(latestMinInstances), String.valueOf(latestMaxInstances));
200         }
201         if (isPropertyChanged(newValues, parentValues, PropertyDefinition.PropertyNames.MAX_INSTANCES) &&
202                 latestMaxInstances < latestInitialCount) {
203             throw new ByActionStatusComponentException(ActionStatus.INVALID_GROUP_PROPERTY_VALUE_LOWER_HIGHER, PropertyDefinition.PropertyNames.MAX_INSTANCES.getPropertyName(), "higher", String.valueOf(latestInitialCount));
204         }
205         if (isPropertyChanged(newValues, parentValues, PropertyDefinition.PropertyNames.MIN_INSTANCES) &&
206                 latestMinInstances > latestInitialCount) {
207             throw new ByActionStatusComponentException(ActionStatus.INVALID_GROUP_PROPERTY_VALUE_LOWER_HIGHER, PropertyDefinition.PropertyNames.MIN_INSTANCES.getPropertyName(), "lower", String.valueOf(latestInitialCount));
208         }
209     }
210
211     private boolean isPropertyChanged(Map<PropertyDefinition.PropertyNames, String> newValues, Map<PropertyDefinition.PropertyNames, String> parentValues, final PropertyDefinition.PropertyNames minInstances) {
212         return newValues.containsKey(minInstances) && !newValues.get(minInstances).equals(parentValues.get(minInstances));
213     }
214
215     private int getLatestIntProperty(Map<PropertyDefinition.PropertyNames, String> newValues, Map<PropertyDefinition.PropertyNames, String> parentValues, PropertyDefinition.PropertyNames propertyKey) {
216         String value;
217         if (newValues.containsKey(propertyKey)) {
218             value = newValues.get(propertyKey);
219         } else {
220             value = parentValues.get(propertyKey);
221         }
222         return Integer.valueOf(value);
223     }
224
225     private boolean isOnlyGroupPropertyValueChanged(GroupProperty groupProperty1, GroupProperty groupProperty2) {
226         GroupProperty groupProperty1Duplicate = new GroupProperty(groupProperty1);
227         groupProperty1Duplicate.setValue(null);
228         groupProperty1Duplicate.setSchema(null);
229         groupProperty1Duplicate.setParentUniqueId(null);
230         GroupProperty groupProperty2Duplicate = new GroupProperty(groupProperty2);
231         groupProperty2Duplicate.setValue(null);
232         groupProperty2Duplicate.setSchema(null);
233         groupProperty2Duplicate.setParentUniqueId(null);
234         return StringUtils.equals(groupProperty1Duplicate.getValueUniqueUid(), groupProperty2Duplicate.getValueUniqueUid())
235                 && groupProperty1Duplicate.equals(groupProperty2Duplicate);
236     }
237
238     private void validateFreeText(GroupProperty groupPropertyToUpdate) {
239         final String groupTypeValue = groupPropertyToUpdate.getValue();
240         if (!org.apache.commons.lang3.StringUtils.isEmpty(groupTypeValue)) {
241             if (!ValidationUtils.validateDescriptionLength(groupTypeValue)) {
242                 throw new ByActionStatusComponentException(ActionStatus.COMPONENT_DESCRIPTION_EXCEEDS_LIMIT,
243                         NodeTypeEnum.Property.getName(),
244                         String.valueOf(ValidationUtils.COMPONENT_DESCRIPTION_MAX_LENGTH));
245             } else if (!ValidationUtils.validateIsEnglish(groupTypeValue)) {
246                 throw new ByActionStatusComponentException(ActionStatus.COMPONENT_INVALID_DESCRIPTION,
247                         NodeTypeEnum.Property.getName());
248             }
249         }
250     }
251
252 }