1 package org.openecomp.sdc.be.components.merge.input;
3 import org.apache.commons.lang.StringUtils;
4 import org.openecomp.sdc.be.dao.utils.MapUtil;
5 import org.openecomp.sdc.be.datatypes.elements.GetInputValueDataDefinition;
6 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
7 import org.openecomp.sdc.be.model.Component;
8 import org.openecomp.sdc.be.model.InputDefinition;
11 import java.util.stream.Collectors;
13 @org.springframework.stereotype.Component
14 public class InputsValuesMergingBusinessLogic {
17 * Merge old inputs values into the updated inputs
18 * An input value is merged if the input previous version had a user defined value and its value is empty in current version
19 * @param oldInputs the currently persisted inputs mapped by their names
20 * @param updatedInputs the currently being update inputs mapped by their names
22 public void mergeComponentInputs(Map<String, InputDefinition> oldInputs, Map<String, InputDefinition> updatedInputs) {
23 updatedInputs.forEach((inputName, input) -> mergeInputsValues(oldInputs.get(inputName), input));
27 * @param oldComponent the old state of {@link Component} that is being updated
28 * @param newComponent the new state of {@link Component} that is being updated
29 * @return a list of all inputs that were previously declared and need to be merged to the updating component
30 * An input needs to merged if a property was declared as an input (by the user) in previous component version and the declared input not exist in new version
32 public List<InputDefinition> getPreviouslyDeclaredInputsToMerge(Component oldComponent, Component newComponent) {
33 if (oldComponent == null || oldComponent.getInputs() == null || newComponent == null ) {
34 return Collections.emptyList();
36 Map<String, List<PropertyDataDefinition>> getInputProperties = getAllGetInputPropertyData(newComponent);
37 List<RedeclareInputData> inputsToRedeclareData = buildRedeclareInputData(newComponent, getInputProperties);
38 return findPrevDeclaredInputs(oldComponent.getInputs(), inputsToRedeclareData);
42 * @param oldInputs list of previous inputs to find inputs to redeclare from
43 * @param newComponent the new state of {@link Component} that is being updated
44 * @param instanceId instance id
45 * @return a list of all inputs that were previously declared and need to be merged to the updating component
46 * An input needs to merged if an instance property was declared as an input (by the user) in previous component version and the declared input not exist in new version
48 public List<InputDefinition> getPreviouslyDeclaredInputsToMerge(List<InputDefinition> oldInputs, Component newComponent, String instanceId) {
49 if (oldInputs == null || newComponent == null ) {
50 return Collections.emptyList();
52 Map<String, List<PropertyDataDefinition>> getInputProperties = getAllGetInputPropertyData(newComponent, instanceId);
53 List<RedeclareInputData> inputsToRedeclareData = buildRedeclareInputData(newComponent, getInputProperties);
54 return findPrevDeclaredInputs(oldInputs, inputsToRedeclareData);
57 private List<InputDefinition> findPrevDeclaredInputs(List<InputDefinition> oldInputs, List<RedeclareInputData> inputsToRedeclareData) {
58 Map<String, InputDefinition> oldInputsById = MapUtil.toMap(oldInputs, InputDefinition::getUniqueId);
59 List<InputDefinition> inputsToRedeclare = new ArrayList<>();
60 inputsToRedeclareData.forEach(redeclareInputData -> {
61 List<InputDefinition> inputDefinitions = prepareInputsForRedeclaration(oldInputsById, redeclareInputData);
62 inputsToRedeclare.addAll(inputDefinitions);
64 return inputsToRedeclare;
67 private List<InputDefinition> prepareInputsForRedeclaration(Map<String, InputDefinition> oldInputsById, RedeclareInputData redeclareInputData) {
68 List<InputDefinition> inputsForRedeclaration = redeclareInputData.declaredInputIds.stream().map(oldInputsById::get).collect(Collectors.toList());
69 inputsForRedeclaration.forEach(input -> {
70 input.setPropertyId(redeclareInputData.propertyId);
71 input.setInstanceUniqueId(redeclareInputData.instanceId);
73 return inputsForRedeclaration;
76 private <T extends PropertyDataDefinition> Map<String, List<PropertyDataDefinition>> findGetInputPropsDefinitions(Map<String, List<T>> instancesPropDefinitions) {
77 Map<String, List<PropertyDataDefinition>> getInputProps = new HashMap<>();
78 if (instancesPropDefinitions == null) {
81 return instancesPropDefinitions.entrySet()
83 .collect(Collectors.toMap(Map.Entry::getKey,
84 entry -> this.filterGetInputProps(entry.getValue())));
87 private <T extends PropertyDataDefinition> List<PropertyDataDefinition> filterGetInputProps(List<T> propDefinitions) {
88 return propDefinitions
90 .filter(PropertyDataDefinition::isGetInputProperty)
91 .collect(Collectors.toList());
94 private void mergeInputsValues(InputDefinition oldInput, InputDefinition updatedInput) {
95 if (shouldMergeOldValue(oldInput, updatedInput)) {
96 updatedInput.setDefaultValue(oldInput.getDefaultValue());
100 private boolean shouldMergeOldValue(InputDefinition oldInput, InputDefinition newInput) {
101 return isNonEmptyDefaultValue(oldInput) && isEmptyDefaultValue(newInput) && isSameType(oldInput, newInput);
104 private boolean isSameType(InputDefinition oldInput, InputDefinition updatedInput) {
105 return oldInput.typeEquals(updatedInput);
108 private boolean isEmptyDefaultValue(InputDefinition input) {
109 return input != null && StringUtils.isEmpty(input.getDefaultValue());
112 private boolean isNonEmptyDefaultValue(InputDefinition input) {
113 return input != null && !isEmptyDefaultValue(input);
116 private List<RedeclareInputData> buildRedeclareInputData(Component newComponent, Map<String, List<PropertyDataDefinition>> getInputProperties) {
117 Map<String, InputDefinition> inputsById = MapUtil.toMap(newComponent.getInputs(), InputDefinition::getUniqueId);
118 List<RedeclareInputData> redeclareInputData = new ArrayList<>();
119 getInputProperties.forEach((instanceId, getInputProps) -> {
120 redeclareInputData.addAll(findInputsToRedeclare(inputsById, instanceId, getInputProps));
122 return redeclareInputData;
126 private Map<String, List<PropertyDataDefinition>> getAllGetInputPropertyData(Component newComponent) {
127 Map<String, List<PropertyDataDefinition>> getInputInstanceProps = findGetInputPropsDefinitions(newComponent.getComponentInstancesProperties());
128 Map<String, List<PropertyDataDefinition>> getInputInstanceInputs = findGetInputPropsDefinitions(newComponent.getComponentInstancesInputs());
129 getInputInstanceInputs.putAll(getInputInstanceProps);
130 return getInputInstanceInputs;
133 private Map<String, List<PropertyDataDefinition>> getAllGetInputPropertyData(Component newComponent, String instanceId) {
134 List<PropertyDataDefinition> getInputInstanceProps = this.filterGetInputProps(newComponent.safeGetComponentInstanceProperties(instanceId));
135 List<PropertyDataDefinition> getInputInstanceInputs = this.filterGetInputProps(newComponent.safeGetComponentInstanceInput(instanceId));
136 getInputInstanceInputs.addAll(getInputInstanceProps);
137 return Collections.singletonMap(instanceId, getInputInstanceInputs);
140 private List<RedeclareInputData> findInputsToRedeclare(Map<String, InputDefinition> inputsById, String instanceId, List<PropertyDataDefinition> getInputProps) {
141 List<RedeclareInputData> redeclareInputDataList = new ArrayList<>();
142 getInputProps.forEach(property -> {
143 List<String> inputsToRedeclareIds = findInputsToRedeclareIds(inputsById, property);
144 RedeclareInputData redeclareInputData = new RedeclareInputData(property.getUniqueId(), inputsToRedeclareIds, instanceId);
145 redeclareInputDataList.add(redeclareInputData);
147 return redeclareInputDataList;
150 private List<String> findInputsToRedeclareIds(Map<String, InputDefinition> inputsById, PropertyDataDefinition property) {
151 List<GetInputValueDataDefinition> getInputValues = property.getGetInputValues();
152 return getInputValues.stream()
153 .filter(getInputVal -> getInputValueWithNoCorrespondingInput(getInputVal, inputsById))
154 .map(GetInputValueDataDefinition::getInputId)
155 .collect(Collectors.toList());
158 private boolean getInputValueWithNoCorrespondingInput(GetInputValueDataDefinition getInputVal, Map<String, InputDefinition> inputsById) {
159 return !inputsById.containsKey(getInputVal.getInputId());
162 private class RedeclareInputData {
163 private String propertyId;
164 private List<String> declaredInputIds;
165 private String instanceId;
167 public RedeclareInputData(String propertyId, List<String> declaredInputIds, String instanceId) {
168 this.propertyId = propertyId;
169 this.declaredInputIds = declaredInputIds;
170 this.instanceId = instanceId;