1 package org.openecomp.sdc.be.components.merge.input;
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.HashMap;
8 import java.util.stream.Collectors;
10 import org.apache.commons.lang.StringUtils;
11 import org.openecomp.sdc.be.dao.utils.MapUtil;
12 import org.openecomp.sdc.be.datatypes.elements.GetInputValueDataDefinition;
13 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
14 import org.openecomp.sdc.be.model.Component;
15 import org.openecomp.sdc.be.model.InputDefinition;
17 @org.springframework.stereotype.Component
18 public class InputsValuesMergingBusinessLogic {
21 * Merge old inputs values into the updated inputs
22 * An input value is merged if the input previous version had a user defined value and its value is empty in current version
23 * @param oldInputs the currently persisted inputs mapped by their names
24 * @param updatedInputs the currently being update inputs mapped by their names
26 public void mergeComponentInputs(Map<String, InputDefinition> oldInputs, Map<String, InputDefinition> updatedInputs) {
27 updatedInputs.forEach((inputName, input) -> mergeInputsValues(oldInputs.get(inputName), input));
31 * @param oldComponent the old state of {@link Component} that is being updated
32 * @param newComponent the new state of {@link Component} that is being updated
33 * @return a list of all inputs that were previously declared and need to be merged to the updating component
34 * 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
36 public List<InputDefinition> getPreviouslyDeclaredInputsToMerge(Component oldComponent, Component newComponent) {
37 if (oldComponent == null || oldComponent.getInputs() == null || newComponent == null ) {
38 return Collections.emptyList();
40 Map<String, List<PropertyDataDefinition>> getInputProperties = getAllGetInputPropertyData(newComponent);
41 List<RedeclareInputData> inputsToRedeclareData = buildRedeclareInputData(newComponent, getInputProperties);
42 return findPrevDeclaredInputs(oldComponent.getInputs(), inputsToRedeclareData);
46 * @param oldInputs list of previous inputs to find inputs to redeclare from
47 * @param newComponent the new state of {@link Component} that is being updated
48 * @param instanceId instance id
49 * @return a list of all inputs that were previously declared and need to be merged to the updating component
50 * 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
52 public List<InputDefinition> getPreviouslyDeclaredInputsToMerge(List<InputDefinition> oldInputs, Component newComponent, String instanceId) {
53 if (oldInputs == null || newComponent == null ) {
54 return Collections.emptyList();
56 Map<String, List<PropertyDataDefinition>> getInputProperties = getAllGetInputPropertyData(newComponent, instanceId);
57 List<RedeclareInputData> inputsToRedeclareData = buildRedeclareInputData(newComponent, getInputProperties);
58 return findPrevDeclaredInputs(oldInputs, inputsToRedeclareData);
61 private List<InputDefinition> findPrevDeclaredInputs(List<InputDefinition> oldInputs, List<RedeclareInputData> inputsToRedeclareData) {
62 Map<String, InputDefinition> oldInputsById = MapUtil.toMap(oldInputs, InputDefinition::getUniqueId);
63 List<InputDefinition> inputsToRedeclare = new ArrayList<>();
64 inputsToRedeclareData.forEach(redeclareInputData -> {
65 List<InputDefinition> inputDefinitions = prepareInputsForRedeclaration(oldInputsById, redeclareInputData);
66 inputsToRedeclare.addAll(inputDefinitions);
68 return inputsToRedeclare;
71 private List<InputDefinition> prepareInputsForRedeclaration(Map<String, InputDefinition> oldInputsById, RedeclareInputData redeclareInputData) {
72 List<InputDefinition> inputsForRedeclaration = redeclareInputData.declaredInputIds.stream().map(oldInputsById::get).collect(Collectors.toList());
73 inputsForRedeclaration.forEach(input -> {
74 input.setPropertyId(redeclareInputData.propertyId);
75 input.setInstanceUniqueId(redeclareInputData.instanceId);
77 return inputsForRedeclaration;
80 private <T extends PropertyDataDefinition> Map<String, List<PropertyDataDefinition>> findGetInputPropsDefinitions(Map<String, List<T>> instancesPropDefinitions) {
81 Map<String, List<PropertyDataDefinition>> getInputProps = new HashMap<>();
82 if (instancesPropDefinitions == null) {
85 return instancesPropDefinitions.entrySet()
87 .collect(Collectors.toMap(Map.Entry::getKey,
88 entry -> this.filterGetInputProps(entry.getValue())));
91 private <T extends PropertyDataDefinition> List<PropertyDataDefinition> filterGetInputProps(List<T> propDefinitions) {
92 return propDefinitions
94 .filter(PropertyDataDefinition::isGetInputProperty)
95 .collect(Collectors.toList());
98 private void mergeInputsValues(InputDefinition oldInput, InputDefinition updatedInput) {
99 if (shouldMergeOldValue(oldInput, updatedInput)) {
100 updatedInput.setDefaultValue(oldInput.getDefaultValue());
104 private boolean shouldMergeOldValue(InputDefinition oldInput, InputDefinition newInput) {
105 return isNonEmptyDefaultValue(oldInput) && isEmptyDefaultValue(newInput) && isSameType(oldInput, newInput);
108 private boolean isSameType(InputDefinition oldInput, InputDefinition updatedInput) {
109 return oldInput.typeEquals(updatedInput);
112 private boolean isEmptyDefaultValue(InputDefinition input) {
113 return input != null && StringUtils.isEmpty(input.getDefaultValue());
116 private boolean isNonEmptyDefaultValue(InputDefinition input) {
117 return input != null && !isEmptyDefaultValue(input);
120 private List<RedeclareInputData> buildRedeclareInputData(Component newComponent, Map<String, List<PropertyDataDefinition>> getInputProperties) {
121 Map<String, InputDefinition> inputsById = MapUtil.toMap(newComponent.getInputs(), InputDefinition::getUniqueId);
122 List<RedeclareInputData> redeclareInputData = new ArrayList<>();
123 getInputProperties.forEach((instanceId, getInputProps) -> {
124 redeclareInputData.addAll(findInputsToRedeclare(inputsById, instanceId, getInputProps));
126 return redeclareInputData;
130 private Map<String, List<PropertyDataDefinition>> getAllGetInputPropertyData(Component newComponent) {
131 Map<String, List<PropertyDataDefinition>> getInputInstanceProps = findGetInputPropsDefinitions(newComponent.getComponentInstancesProperties());
132 Map<String, List<PropertyDataDefinition>> getInputInstanceInputs = findGetInputPropsDefinitions(newComponent.getComponentInstancesInputs());
133 getInputInstanceInputs.putAll(getInputInstanceProps);
134 return getInputInstanceInputs;
137 private Map<String, List<PropertyDataDefinition>> getAllGetInputPropertyData(Component newComponent, String instanceId) {
138 List<PropertyDataDefinition> getInputInstanceProps = this.filterGetInputProps(newComponent.safeGetComponentInstanceProperties(instanceId));
139 List<PropertyDataDefinition> getInputInstanceInputs = this.filterGetInputProps(newComponent.safeGetComponentInstanceInput(instanceId));
140 getInputInstanceInputs.addAll(getInputInstanceProps);
141 return Collections.singletonMap(instanceId, getInputInstanceInputs);
144 private List<RedeclareInputData> findInputsToRedeclare(Map<String, InputDefinition> inputsById, String instanceId, List<PropertyDataDefinition> getInputProps) {
145 List<RedeclareInputData> redeclareInputDataList = new ArrayList<>();
146 getInputProps.forEach(property -> {
147 List<String> inputsToRedeclareIds = findInputsToRedeclareIds(inputsById, property);
148 RedeclareInputData redeclareInputData = new RedeclareInputData(property.getUniqueId(), inputsToRedeclareIds, instanceId);
149 redeclareInputDataList.add(redeclareInputData);
151 return redeclareInputDataList;
154 private List<String> findInputsToRedeclareIds(Map<String, InputDefinition> inputsById, PropertyDataDefinition property) {
155 List<GetInputValueDataDefinition> getInputValues = property.getGetInputValues();
156 return getInputValues.stream()
157 .filter(getInputVal -> getInputValueWithNoCorrespondingInput(getInputVal, inputsById))
158 .map(GetInputValueDataDefinition::getInputId)
159 .collect(Collectors.toList());
162 private boolean getInputValueWithNoCorrespondingInput(GetInputValueDataDefinition getInputVal, Map<String, InputDefinition> inputsById) {
163 return !inputsById.containsKey(getInputVal.getInputId());
166 private class RedeclareInputData {
167 private String propertyId;
168 private List<String> declaredInputIds;
169 private String instanceId;
171 public RedeclareInputData(String propertyId, List<String> declaredInputIds, String instanceId) {
172 this.propertyId = propertyId;
173 this.declaredInputIds = declaredInputIds;
174 this.instanceId = instanceId;