Sync Integ to Master
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / merge / property / PropertyValueMerger.java
1 package org.openecomp.sdc.be.components.merge.property;
2
3 import org.apache.commons.lang.StringUtils;
4 import org.openecomp.sdc.be.components.impl.ImportUtils;
5
6 import java.util.ArrayList;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.stream.Collectors;
10
11 public abstract class PropertyValueMerger {
12
13     abstract Object merge(Object oldVal, Object newVal, List<String> someStrings);
14
15     @SuppressWarnings("unchecked")
16     /**
17      * merges property value oldVal into property value newVal recursively
18      * @param oldVal - cannot be {@code Null}
19      */
20     protected Object mergeValues(Object oldVal, Object newVal, List<String> getInputNamesToMerge) {
21         if (isEmptyValue(newVal)) {
22             return removeUnwantedGetInputValues(oldVal, getInputNamesToMerge);
23         }
24         if (isMapTypeValues(oldVal, newVal)) {
25             return mergeMapValue((Map<String, Object>) oldVal, (Map<String, Object>) newVal, getInputNamesToMerge);
26         }
27         if (isListTypeValues(oldVal, newVal)) {
28             return mergeListValue((List<Object>) oldVal, (List<Object>) newVal, getInputNamesToMerge);
29         }
30         if (isSameTypeValues(oldVal, newVal)) {
31             return mergeScalarValue(oldVal, newVal);
32         }
33         return newVal;
34
35     }
36
37     private Map<String, Object> mergeMapValue(Map<String, Object> oldValMap, Map<String, Object> newValMap, List<String> getInputNamesToMerge) {
38         mergeEntriesExistInNewValue(oldValMap, newValMap, getInputNamesToMerge);//continue the recursion
39         setOldEntriesNotExistInNewValue(oldValMap, newValMap, getInputNamesToMerge);
40         return newValMap;
41     }
42
43     private void mergeEntriesExistInNewValue(Map<String, Object> oldValMap, Map<String, Object> newValMap, List<String> getInputNamesToMerge) {
44         for (Map.Entry<String, Object> newValEntry : newValMap.entrySet()) {
45             Object oldVal = oldValMap.get(newValEntry.getKey());
46             if (oldVal != null) {
47                 newValMap.put(newValEntry.getKey(), merge(oldVal, newValEntry.getValue(), getInputNamesToMerge));
48             }
49         }
50     }
51
52     private void setOldEntriesNotExistInNewValue(Map<String, Object> oldVal, Map<String, Object> newVal, List<String> getInputNamesToMerge) {
53         for (Map.Entry<String, Object> oldValEntry : oldVal.entrySet()) {
54             if (!isGetInputEntry(oldValEntry) || isGetInputToMerge(getInputNamesToMerge, oldValEntry)) {
55                 Object oldValObj = oldValEntry.getValue();
56                 newVal.computeIfAbsent(oldValEntry.getKey(), key -> removeUnwantedGetInputValues(oldValObj, getInputNamesToMerge));
57             }
58         }
59     }
60
61     private List<Object> mergeListValue(List<Object> oldVal, List<Object> newVal, List<String> getInputNamesToMerge) {
62         List<Object> mergedList = mergeLists(oldVal, newVal, getInputNamesToMerge);
63         copyRestOfBiggerList(oldVal, newVal, getInputNamesToMerge, mergedList);
64         return mergedList;
65     }
66
67     private void copyRestOfBiggerList(List<Object> oldVal, List<Object> newVal, List<String> getInputNamesToMerge, List<Object> mergedList) {
68         if (oldVal.size() == newVal.size()) {
69             return;
70         }
71         int maxListSize = Math.max(oldVal.size(), newVal.size());
72         List<Object> greaterList = newVal.size() == maxListSize ? newVal : oldVal;
73         for (int i = mergedList.size(); i < maxListSize; i ++) {
74             Object listVal = greaterList.get(i);
75             Object listValToMerge = greaterList == oldVal ? removeUnwantedGetInputValues(listVal, getInputNamesToMerge) : listVal;
76             mergedList.add(listValToMerge);
77         }
78     }
79
80     private List<Object> mergeLists(List<Object> oldVal, List<Object> newVal, List<String> getInputNamesToMerge) {
81         int minListSize = Math.min(oldVal.size(), newVal.size());
82         List<Object> mergedList = new ArrayList<>();
83         for (int i = 0; i < minListSize; i++) {
84             Object mergedVal = merge(oldVal.get(i), newVal.get(i), getInputNamesToMerge);
85             mergedList.add(mergedVal);
86         }
87         return mergedList;
88     }
89
90     Object mergeScalarValue(Object oldVal, Object newVal) {
91         return isEmptyValue(newVal) ? oldVal : newVal;
92     }
93
94     @SuppressWarnings("unchecked")
95     Object removeUnwantedGetInputValues(Object val, List<String> getInputNamesToMerge) {
96         if (val instanceof  Map) {
97             return removeUnwantedGetInputValues((Map<String, Object>) val, getInputNamesToMerge);
98         }
99         if (val instanceof List) {
100             return removeUnwantedGetInputValues((List<Object>)val, getInputNamesToMerge);
101         }
102         return val;
103     }
104
105     private List<Object> removeUnwantedGetInputValues(List<Object> listVal, List<String> getInputNamesToMerge) {
106         return listVal.stream().map(val -> removeUnwantedGetInputValues(val, getInputNamesToMerge)).collect(Collectors.toList());
107     }
108
109     private Map<String, Object> removeUnwantedGetInputValues(Map<String, Object> val, List<String> getInputNamesToMerge) {
110         return val.entrySet().stream().filter(entry -> !isGetInputEntry(entry) || isGetInputToMerge(getInputNamesToMerge, entry))
111                 .collect(Collectors.toMap(Map.Entry::getKey, entry -> removeUnwantedGetInputValues(entry.getValue(), getInputNamesToMerge)));
112     }
113
114     private boolean isGetInputToMerge(List<String> getInputNamesToMerge, Map.Entry<String, Object> entry) {
115         return getInputNamesToMerge.contains(retrieveGetInputInputName(entry.getValue()));
116     }
117
118     private boolean isMapTypeValues(Object oldVal, Object newVal) {
119         return newVal instanceof Map && oldVal instanceof Map;
120     }
121
122     private boolean isListTypeValues(Object oldVal, Object newVal) {
123         return newVal instanceof List && oldVal instanceof List;
124     }
125
126     private boolean isSameTypeValues(Object oldVal, Object newVal) {
127         return oldVal.getClass().equals(newVal.getClass());
128     }
129
130     private String retrieveGetInputInputName(Object getInputValue) {
131         return getInputValue instanceof List ? (String)((List) getInputValue).get(0) : (String)getInputValue;
132     }
133
134     private boolean isGetInputEntry(Map.Entry<String, Object> oldValEntry) {
135         return oldValEntry.getKey().equals(ImportUtils.ToscaTagNamesEnum.GET_INPUT.getElementName());
136     }
137
138     private boolean isEmptyValue(Object val) {
139         return val == null ||
140                val instanceof String && StringUtils.isEmpty((String)val) ||
141                val instanceof Map && ((Map) val).isEmpty() ||
142                val instanceof List && ((List) val).isEmpty();
143
144
145     }
146
147
148 }