package org.openecomp.sdc.be.components.merge.property; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.apache.commons.lang.StringUtils; import org.openecomp.sdc.be.components.impl.ImportUtils; public abstract class PropertyValueMerger { abstract Object merge(Object oldVal, Object newVal, List someStrings); @SuppressWarnings("unchecked") /** * merges property value oldVal into property value newVal recursively * @param oldVal - cannot be {@code Null} */ protected Object mergeValues(Object oldVal, Object newVal, List getInputNamesToMerge) { if (isEmptyValue(newVal)) { return removeUnwantedGetInputValues(oldVal, getInputNamesToMerge); } if (isMapTypeValues(oldVal, newVal)) { return mergeMapValue((Map) oldVal, (Map) newVal, getInputNamesToMerge); } if (isListTypeValues(oldVal, newVal)) { return mergeListValue((List) oldVal, (List) newVal, getInputNamesToMerge); } if (isSameTypeValues(oldVal, newVal)) { return mergeScalarValue(oldVal, newVal); } return newVal; } private Map mergeMapValue(Map oldValMap, Map newValMap, List getInputNamesToMerge) { mergeEntriesExistInNewValue(oldValMap, newValMap, getInputNamesToMerge);//continue the recursion setOldEntriesNotExistInNewValue(oldValMap, newValMap, getInputNamesToMerge); return newValMap; } private void mergeEntriesExistInNewValue(Map oldValMap, Map newValMap, List getInputNamesToMerge) { for (Map.Entry newValEntry : newValMap.entrySet()) { Object oldVal = oldValMap.get(newValEntry.getKey()); if (oldVal != null) { newValMap.put(newValEntry.getKey(), merge(oldVal, newValEntry.getValue(), getInputNamesToMerge)); } } } private void setOldEntriesNotExistInNewValue(Map oldVal, Map newVal, List getInputNamesToMerge) { for (Map.Entry oldValEntry : oldVal.entrySet()) { if (!isGetInputEntry(oldValEntry) || isGetInputToMerge(getInputNamesToMerge, oldValEntry)) { Object oldValObj = oldValEntry.getValue(); newVal.computeIfAbsent(oldValEntry.getKey(), key -> removeUnwantedGetInputValues(oldValObj, getInputNamesToMerge)); } } } private List mergeListValue(List oldVal, List newVal, List getInputNamesToMerge) { List mergedList = mergeLists(oldVal, newVal, getInputNamesToMerge); copyRestOfBiggerList(oldVal, newVal, getInputNamesToMerge, mergedList); return mergedList; } private void copyRestOfBiggerList(List oldVal, List newVal, List getInputNamesToMerge, List mergedList) { if (oldVal.size() == newVal.size()) { return; } int maxListSize = Math.max(oldVal.size(), newVal.size()); List greaterList = newVal.size() == maxListSize ? newVal : oldVal; for (int i = mergedList.size(); i < maxListSize; i ++) { Object listVal = greaterList.get(i); Object listValToMerge = greaterList == oldVal ? removeUnwantedGetInputValues(listVal, getInputNamesToMerge) : listVal; mergedList.add(listValToMerge); } } private List mergeLists(List oldVal, List newVal, List getInputNamesToMerge) { int minListSize = Math.min(oldVal.size(), newVal.size()); List mergedList = new ArrayList<>(); for (int i = 0; i < minListSize; i++) { Object mergedVal = merge(oldVal.get(i), newVal.get(i), getInputNamesToMerge); mergedList.add(mergedVal); } return mergedList; } Object mergeScalarValue(Object oldVal, Object newVal) { return isEmptyValue(newVal) ? oldVal : newVal; } @SuppressWarnings("unchecked") Object removeUnwantedGetInputValues(Object val, List getInputNamesToMerge) { if (val instanceof Map) { return removeUnwantedGetInputValues((Map) val, getInputNamesToMerge); } if (val instanceof List) { return removeUnwantedGetInputValues((List)val, getInputNamesToMerge); } return val; } private List removeUnwantedGetInputValues(List listVal, List getInputNamesToMerge) { return listVal.stream().map(val -> removeUnwantedGetInputValues(val, getInputNamesToMerge)).collect(Collectors.toList()); } private Map removeUnwantedGetInputValues(Map val, List getInputNamesToMerge) { return val.entrySet().stream().filter(entry -> !isGetInputEntry(entry) || isGetInputToMerge(getInputNamesToMerge, entry)) .collect(Collectors.toMap(Map.Entry::getKey, entry -> removeUnwantedGetInputValues(entry.getValue(), getInputNamesToMerge))); } private boolean isGetInputToMerge(List getInputNamesToMerge, Map.Entry entry) { return getInputNamesToMerge.contains(retrieveGetInputInputName(entry.getValue())); } private boolean isMapTypeValues(Object oldVal, Object newVal) { return newVal instanceof Map && oldVal instanceof Map; } private boolean isListTypeValues(Object oldVal, Object newVal) { return newVal instanceof List && oldVal instanceof List; } private boolean isSameTypeValues(Object oldVal, Object newVal) { return oldVal.getClass().equals(newVal.getClass()); } private String retrieveGetInputInputName(Object getInputValue) { return getInputValue instanceof List ? (String)((List) getInputValue).get(0) : (String)getInputValue; } private boolean isGetInputEntry(Map.Entry oldValEntry) { return oldValEntry.getKey().equals(ImportUtils.ToscaTagNamesEnum.GET_INPUT.getElementName()); } private boolean isEmptyValue(Object val) { return val == null || val instanceof String && StringUtils.isEmpty((String)val) || val instanceof Map && ((Map) val).isEmpty() || val instanceof List && ((List) val).isEmpty(); } }