1 package org.openecomp.sdc.be.components.merge.property;
3 import java.util.ArrayList;
4 import java.util.Collections;
7 import java.util.Optional;
8 import java.util.stream.Collectors;
10 import javax.annotation.Resource;
12 import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
13 import org.openecomp.sdc.be.datatypes.elements.GetInputValueDataDefinition;
14 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
15 import org.openecomp.sdc.be.model.DataTypeDefinition;
16 import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache;
17 import org.openecomp.sdc.be.model.tosca.ToscaFunctions;
18 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
19 import org.openecomp.sdc.be.tosca.PropertyConvertor;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22 import org.springframework.stereotype.Component;
24 import com.google.gson.Gson;
26 import fj.data.Either;
29 public class PropertyDataValueMergeBusinessLogic {
31 private static final Logger LOGGER = LoggerFactory.getLogger(PropertyDataValueMergeBusinessLogic.class);
33 private final PropertyConvertor propertyConvertor = PropertyConvertor.getInstance();
35 private PropertyValueMerger complexPropertyValueMerger = ComplexPropertyValueMerger.getInstance();
37 private PropertyValueMerger scalarPropertyValueMerger = ScalarPropertyValueMerger.getInstance();
40 private ApplicationDataTypeCache dataTypeCache;
42 private final Gson gson = new Gson();
46 * @param oldProp the old property to merge value from
47 * @param newProp the new property to merge value into
48 * @param getInputNamesToMerge inputs names which their corresponding get_input values are allowed to be merged
50 public void mergePropertyValue(PropertyDataDefinition oldProp, PropertyDataDefinition newProp, List<String> getInputNamesToMerge) {
51 Either<Map<String, DataTypeDefinition>, TitanOperationStatus> dataTypesEither = dataTypeCache.getAll();
52 if (dataTypesEither.isRight()) {
53 LOGGER.debug("failed to fetch data types, skip merging of previous property values. status: {}", dataTypesEither.right().value());
55 mergePropertyValue(oldProp, newProp, dataTypesEither.left().value(), getInputNamesToMerge);
56 mergeComplexPropertyGetInputsValues(oldProp, newProp);
59 private void mergePropertyValue(PropertyDataDefinition oldProp, PropertyDataDefinition newProp, Map<String, DataTypeDefinition> dataTypes, List<String> getInputNamesToMerge) {
60 Object oldValAsObject = convertPropertyStrValueToObject(oldProp, dataTypes);
61 Object newValAsObject = convertPropertyStrValueToObject(newProp, dataTypes);
62 PropertyValueMerger propertyValueMerger = getPropertyValueMerger(newProp);
63 if(oldValAsObject != null){
64 Object mergedValue = propertyValueMerger.mergeValues(oldValAsObject, newValAsObject, getInputNamesToMerge);
65 newProp.setValue(convertPropertyValueObjectToString(mergedValue));
69 private PropertyValueMerger getPropertyValueMerger(PropertyDataDefinition newProp) {
70 if (ToscaPropertyType.isPrimitiveType(newProp.getType()) || ToscaPropertyType.isPrimitiveType(newProp.getSchemaType())) {
71 return scalarPropertyValueMerger;
73 return complexPropertyValueMerger;
76 private String convertPropertyValueObjectToString(Object mergedValue) {
77 if (isEmptyValue(mergedValue)) {
80 return mergedValue instanceof String? mergedValue.toString() : gson.toJson(mergedValue);
83 private Object convertPropertyStrValueToObject(PropertyDataDefinition propertyDataDefinition, Map<String, DataTypeDefinition> dataTypes) {
84 String propValue = propertyDataDefinition.getValue() == null ? "": propertyDataDefinition.getValue();
85 String propertyType = propertyDataDefinition.getType();
86 String innerType = propertyDataDefinition.getSchemaType();
87 return propertyConvertor.convertToToscaObject(propertyType, propValue, innerType, dataTypes);
90 private boolean isEmptyValue(Object val) {
92 val instanceof Map && ((Map) val).isEmpty() ||
93 val instanceof List && ((List) val).isEmpty();
96 private void mergeComplexPropertyGetInputsValues(PropertyDataDefinition oldProp, PropertyDataDefinition newProp) {
97 if (!oldProp.isGetInputProperty()) {
100 List<GetInputValueDataDefinition> getInputsToMerge = findOldGetInputValuesToMerge(oldProp, newProp);
101 List<GetInputValueDataDefinition> newPropGetInputValues = Optional.ofNullable(newProp.getGetInputValues()).orElse(new ArrayList<>());
102 newPropGetInputValues.addAll(getInputsToMerge);
103 newProp.setGetInputValues(newPropGetInputValues);
106 private List<GetInputValueDataDefinition> findOldGetInputValuesToMerge(PropertyDataDefinition oldProp, PropertyDataDefinition newProp) {
107 List<GetInputValueDataDefinition> oldGetInputValues = oldProp.getGetInputValues();
108 List<GetInputValueDataDefinition> newGetInputValues = Optional.ofNullable(newProp.getGetInputValues()).orElse(Collections.emptyList());
109 List<String> newGetInputNames = newGetInputValues.stream().map(GetInputValueDataDefinition::getInputName).collect(Collectors.toList());
110 return oldGetInputValues.stream()
111 .filter(getInput -> !newGetInputNames.contains(getInput.getInputName()))
112 .filter(getInput -> isValueContainsGetInput(getInput.getInputName(), newProp.getValue()))
113 .collect(Collectors.toList());
116 private boolean isValueContainsGetInput(String inputName, String value) {
117 String getInputEntry = "\"%s\":\"%s\"";
118 return value != null && value.contains(String.format(getInputEntry, ToscaFunctions.GET_INPUT.getFunctionName(), inputName));