From 9699b67917b34c1a10536d353cef09d8904354a6 Mon Sep 17 00:00:00 2001 From: MichaelMorris Date: Wed, 7 Sep 2022 15:28:21 +0100 Subject: Import services with sub prop tosca functions Includes fix for setting sub properties to yaml values other than maps Signed-off-by: MichaelMorris Issue-ID: SDC-4168 Change-Id: I15e3c450c10d4603f882c20f2da80cb7b5d80bb6 --- .../csar/YamlTemplateParsingHandler.java | 36 ++++++- .../impl/ComponentInstanceBusinessLogic.java | 9 +- .../impl/ServiceImportBusinessLogic.java | 81 ++++++++++++++-- .../be/components/impl/ToscaFunctionService.java | 105 ++++++++++++++------- 4 files changed, 184 insertions(+), 47 deletions(-) (limited to 'catalog-be/src/main') diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandler.java index 82aa1343c1..09a84887aa 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandler.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandler.java @@ -30,7 +30,6 @@ import static org.openecomp.sdc.be.components.impl.ImportUtils.findFirstToscaLis import static org.openecomp.sdc.be.components.impl.ImportUtils.findFirstToscaMapElement; import static org.openecomp.sdc.be.components.impl.ImportUtils.findToscaElement; import static org.openecomp.sdc.be.components.impl.ImportUtils.loadYamlAsStrictMap; -import static org.openecomp.sdc.be.datatypes.enums.MetadataKeyEnum.NAME; import static org.openecomp.sdc.be.model.tosca.ToscaType.STRING; import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.ARTIFACTS; import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.ATTRIBUTES; @@ -104,9 +103,11 @@ import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; import org.openecomp.sdc.be.datatypes.elements.PolicyTargetType; import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.PropertyFilterConstraintDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.SubPropertyToscaFunction; import org.openecomp.sdc.be.datatypes.elements.SubstitutionFilterPropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ToscaFunction; import org.openecomp.sdc.be.datatypes.enums.ConstraintType; +import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionType; import org.openecomp.sdc.be.datatypes.enums.FilterValueType; import org.openecomp.sdc.be.datatypes.enums.PropertyFilterTargetType; import org.openecomp.sdc.be.model.CapabilityDefinition; @@ -369,6 +370,7 @@ public class YamlTemplateParsingHandler { final PropertyDefinition propertyDefinition = new PropertyDefinition(originalProperty); propertyDefinition.setValue(gson.toJson(uploadPropInfo.getValue())); propertyDefinition.setToscaFunction(uploadPropInfo.getToscaFunction()); + propertyDefinition.setSubPropertyToscaFunctions(uploadPropInfo.getSubPropertyToscaFunctions()); propertyDefinition.setGetInputValues(uploadPropInfo.getGet_input()); propertyDefinition.setDescription(uploadPropInfo.getDescription()); return propertyDefinition; @@ -623,6 +625,7 @@ public class YamlTemplateParsingHandler { private void mergeGroupProperty(final PropertyDataDefinition property, final Object propertyYaml) { final UploadPropInfo uploadPropInfo = buildProperty(property.getName(), propertyYaml); property.setToscaFunction(uploadPropInfo.getToscaFunction()); + property.setSubPropertyToscaFunctions(uploadPropInfo.getSubPropertyToscaFunctions()); property.setValue(convertPropertyValue(ToscaPropertyType.isValidType(property.getType()), uploadPropInfo.getValue())); property.setGetInputValues(uploadPropInfo.getGet_input()); } @@ -1183,6 +1186,16 @@ public class YamlTemplateParsingHandler { } if (toscaFunctionYamlParsingHandler.isPropertyValueToscaFunction(propValueObj)) { toscaFunctionYamlParsingHandler.buildToscaFunctionBasedOnPropertyValue(propValueMap).ifPresent(propertyDef::setToscaFunction); + } else { + final Collection subPropertyToscaFunctions = buildSubPropertyToscaFunctions(propValueMap, new ArrayList<>()); + if (CollectionUtils.isNotEmpty(subPropertyToscaFunctions)) { + Collection existingSubPropertyToscaFunctions = propertyDef.getSubPropertyToscaFunctions(); + if (existingSubPropertyToscaFunctions == null) { + propertyDef.setSubPropertyToscaFunctions(subPropertyToscaFunctions); + } else { + propertyDef.getSubPropertyToscaFunctions().addAll(subPropertyToscaFunctions); + } + } } if (propValueMap.containsKey(DESCRIPTION.getElementName())) { propertyDef.setDescription((propValueMap).get(DESCRIPTION.getElementName()).toString()); @@ -1201,6 +1214,27 @@ public class YamlTemplateParsingHandler { } return propertyDef; } + + private Collection buildSubPropertyToscaFunctions(final Map propValueMap, final List path) { + Collection subPropertyToscaFunctions = new ArrayList<>(); + propValueMap.entrySet().stream().filter(entry -> entry.getValue() instanceof Map).forEach(entry -> { + List subPropertyPath = new ArrayList<>(path); + subPropertyPath.add(entry.getKey()); + if (ToscaFunctionType.findType(((Map) entry.getValue()).keySet().iterator().next()).isPresent()) { + Optional toscaFunction = + toscaFunctionYamlParsingHandler.buildToscaFunctionBasedOnPropertyValue((Map) entry.getValue()); + if (toscaFunction.isPresent()) { + SubPropertyToscaFunction subPropertyToscaFunction = new SubPropertyToscaFunction(); + subPropertyToscaFunction.setToscaFunction(toscaFunction.get()); + subPropertyToscaFunction.setSubPropertyPath(subPropertyPath); + subPropertyToscaFunctions.add(subPropertyToscaFunction); + } + } else { + subPropertyToscaFunctions.addAll(buildSubPropertyToscaFunctions((Map) entry.getValue(), subPropertyPath)); + } + }); + return subPropertyToscaFunctions; + } private UploadInterfaceInfo buildInterface(String interfaceName, Object interfaceValue) { UploadInterfaceInfo interfaceDef = new UploadInterfaceInfo(); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java index 684645a7b2..9e04572075 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java @@ -145,6 +145,7 @@ import org.openecomp.sdc.common.log.wrappers.Logger; import org.openecomp.sdc.common.util.ValidationUtils; import org.openecomp.sdc.exception.ResponseFormat; import org.springframework.beans.factory.annotation.Autowired; +import org.yaml.snakeyaml.Yaml; @org.springframework.stereotype.Component public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { @@ -1968,6 +1969,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { toscaFunctionValidator.validate(property, containerComponent); property.setValue(property.getToscaFunction().getValue()); } + if (CollectionUtils.isNotEmpty(property.getSubPropertyToscaFunctions())){ final JSONObject jObject = property.getValue() == null ? new JSONObject() : new JSONObject(property.getValue()); property.getSubPropertyToscaFunctions().stream().forEach(subToscaFunction -> { @@ -2022,11 +2024,8 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { private void setJsonObjectForSubProperty(final JSONObject jObject, final List path, String value) { if (path.size() == 1) { - if (!value.startsWith("{")) { - value = new StringBuilder("{").append(value).append("}").toString(); - } - final JSONObject jObjectSub = new JSONObject(value); - jObject.put(path.get(0), jObjectSub); + Object valueAsObject = new Yaml().loadAs(value, Object.class); + jObject.put(path.get(0), valueAsObject); } else { if (!jObject.has(path.get(0))) { jObject.put(path.get(0), new JSONObject()); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java index 8c46285240..ccf7e5cb73 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java @@ -25,6 +25,9 @@ import static org.openecomp.sdc.be.components.impl.ImportUtils.getPropertyJsonSt import static org.openecomp.sdc.be.tosca.CsarUtils.VF_NODE_TYPE_ARTIFACTS_PATH_PATTERN; import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import fj.data.Either; import java.util.ArrayList; import java.util.Collection; @@ -40,6 +43,7 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; +import java.util.stream.Collectors; import lombok.Getter; import lombok.Setter; import org.apache.commons.collections.CollectionUtils; @@ -78,6 +82,7 @@ import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; import org.openecomp.sdc.be.datatypes.elements.PolicyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.SubstitutionFilterPropertyDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.SubPropertyToscaFunction; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; @@ -131,6 +136,7 @@ import org.openecomp.sdc.be.model.operations.StorageException; import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; +import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; import org.openecomp.sdc.be.tosca.CsarUtils; import org.openecomp.sdc.be.tosca.ToscaExportHandler; @@ -1892,10 +1898,17 @@ public class ServiceImportBusinessLogic { } } final var property = new ComponentInstanceProperty(curPropertyDef, value, null); - String validatePropValue = serviceBusinessLogic.validatePropValueBeforeCreate(property, value, isValidate, allDataTypes); - property.setValue(validatePropValue); + String validatedPropValue = serviceBusinessLogic.validatePropValueBeforeCreate(property, value, true, allDataTypes); - if (tryHandlingAsYamlToscaFunction(validatePropValue, value, propertyInfo)) { + addSubPropertyYamlToscaFunctions(validatedPropValue, value, property.getType(), propertyInfo, allDataTypes); + + if (CollectionUtils.isNotEmpty(propertyInfo.getSubPropertyToscaFunctions())) { + validatedPropValue = value; + } + + property.setValue(validatedPropValue); + + if (tryHandlingAsYamlToscaFunction(validatedPropValue, value, propertyInfo)) { try { final Object yamlValue = new Yaml().loadAs(value, Object.class); CustomYamlFunction toscaFunction = new CustomYamlFunction(); @@ -1907,7 +1920,8 @@ public class ServiceImportBusinessLogic { } else { property.setToscaFunction(propertyInfo.getToscaFunction()); } - if (!getInputs.isEmpty()) { + property.setSubPropertyToscaFunctions(propertyInfo.getSubPropertyToscaFunctions()); + if (!getInputs.isEmpty() && CollectionUtils.isEmpty(property.getSubPropertyToscaFunctions())) { final List getInputValues = new ArrayList<>(); for (final GetInputValueDataDefinition getInput : getInputs) { final List inputs = component.getInputs(); @@ -1941,8 +1955,63 @@ public class ServiceImportBusinessLogic { return componentsUtils.getResponseFormat(ActionStatus.OK); } - private boolean tryHandlingAsYamlToscaFunction(String validatePropValue, String value, UploadPropInfo propertyInfo) { - return StringUtils.isEmpty(validatePropValue) && StringUtils.isNotEmpty(value) && propertyInfo.getToscaFunction() == null; + private boolean tryHandlingAsYamlToscaFunction(String validatedPropValue, String value, UploadPropInfo propertyInfo) { + return StringUtils.isEmpty(validatedPropValue) && StringUtils.isNotEmpty(value) && propertyInfo.getToscaFunction() == null && CollectionUtils.isEmpty(propertyInfo.getSubPropertyToscaFunctions()); + } + + private void addSubPropertyYamlToscaFunctions(final String validatedPropValue, final String value, final String propertyType, final UploadPropInfo propertyInfo, final Map allDataTypes) { + if (StringUtils.isNotEmpty(validatedPropValue) || StringUtils.isEmpty(value) || ToscaPropertyType.isValidType(propertyType) != null) { + return; + } + try { + final JsonObject jsonObject = JsonParser.parseString(value).getAsJsonObject(); + + final DataTypeDefinition dataTypeDefinition = allDataTypes.get(propertyType); + final List propertyNames = + dataTypeDefinition.getProperties().stream().map(PropertyDataDefinition::getName).collect(Collectors.toList()); + + boolean hasSubPropertyValues = jsonObject.entrySet().stream().allMatch(entry -> propertyNames.contains(entry.getKey())); + + if (hasSubPropertyValues) { + for (final PropertyDefinition prop : dataTypeDefinition.getProperties()) { + if (propertyInfo.getSubPropertyToscaFunctions().stream() + .anyMatch(subPropertyToscaFunction -> subPropertyToscaFunction.getSubPropertyPath().get(0).equals(prop.getName()))) { + continue; + } + Optional subPropertyToscaFunction = createSubPropertyYamlToscaFunction(jsonObject, prop, allDataTypes); + if (subPropertyToscaFunction.isPresent()) { + propertyInfo.getSubPropertyToscaFunctions().add(subPropertyToscaFunction.get()); + } + } + } + } catch (Exception exception) { + log.info("Cannot create YAML value for {}", value); + } + } + + private Optional createSubPropertyYamlToscaFunction(final JsonObject jsonObject, final PropertyDefinition prop, final Map allDataTypes) { + JsonElement propJsonElement = jsonObject.get(prop.getName()); + if (propJsonElement != null) { + final String subPropValue = propJsonElement.toString(); + final ComponentInstanceProperty subProperty = new ComponentInstanceProperty(prop, subPropValue, null); + final String validateSubPropValue = + serviceBusinessLogic.validatePropValueBeforeCreate(subProperty, subPropValue, true, allDataTypes); + + if (StringUtils.isEmpty(validateSubPropValue) && StringUtils.isNotEmpty(subPropValue)) { + try { + Object yamlValue = new Yaml().loadAs(subPropValue, Object.class); + SubPropertyToscaFunction subPropertyToscaFunction = new SubPropertyToscaFunction(); + CustomYamlFunction toscaFunction = new CustomYamlFunction(); + toscaFunction.setYamlValue(yamlValue); + subPropertyToscaFunction.setToscaFunction(toscaFunction); + subPropertyToscaFunction.setSubPropertyPath(Collections.singletonList(prop.getName())); + return Optional.of(subPropertyToscaFunction); + } catch (Exception exception) { + log.info("Cannot create YAML value for {}", subPropValue); + } + } + } + return Optional.empty(); } protected ResponseFormat addInterfaceValuesToRi( diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ToscaFunctionService.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ToscaFunctionService.java index 28843af54a..3a89e85a4f 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ToscaFunctionService.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ToscaFunctionService.java @@ -23,6 +23,9 @@ package org.openecomp.sdc.be.components.impl; import java.util.List; import java.util.Map; +import java.util.Optional; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.openecomp.sdc.be.datatypes.elements.ToscaConcatFunction; import org.openecomp.sdc.be.datatypes.elements.ToscaFunction; import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionType; @@ -115,43 +118,75 @@ public class ToscaFunctionService { if (toscaGetFunction.getPropertySource() == PropertySource.SELF) { toscaGetFunction.setSourceUniqueId(selfComponent.getUniqueId()); toscaGetFunction.setSourceName(selfComponent.getName()); - if (toscaGetFunction.getType() == ToscaFunctionType.GET_PROPERTY) { - selfComponent.getProperties().stream() - .filter(property -> property.getName().equals(toscaGetFunction.getPropertyPathFromSource().get(0))) - .findAny() - .ifPresent(property -> - toscaGetFunction.setPropertyUniqueId(property.getUniqueId()) - ); - } else { - selfComponent.getAttributes().stream() - .filter(attribute -> attribute.getName().equals(toscaGetFunction.getPropertyPathFromSource().get(0))) - .findAny() - .ifPresent(attribute -> - toscaGetFunction.setPropertyUniqueId(attribute.getUniqueId()) - ); + if (isGetAttributeAndComponentHasAttributes(toscaGetFunction, selfComponent)) { + setPropertyIdFromAttribute(selfComponent, toscaGetFunction); } - } else if (toscaGetFunction.getPropertySource() == PropertySource.INSTANCE) { - selfComponent.getComponentInstances().stream() - .filter(componentInstance -> toscaGetFunction.getSourceName().equals(componentInstance.getName())) - .findAny() - .ifPresent(componentInstance -> toscaGetFunction.setSourceUniqueId(componentInstance.getUniqueId())); - if (toscaGetFunction.getType() == ToscaFunctionType.GET_PROPERTY) { - final List instanceProperties = instancePropertyMap.get(toscaGetFunction.getSourceUniqueId()); - instanceProperties.stream() - .filter(property -> property.getName().equals(toscaGetFunction.getPropertyPathFromSource().get(0))) - .findAny() - .ifPresent(property -> - toscaGetFunction.setPropertyUniqueId(property.getUniqueId()) - ); - } else { - final List instanceAttributes = instanceAttributeMap.get(toscaGetFunction.getSourceUniqueId()); - instanceAttributes.stream() - .filter(attribute -> attribute.getName().equals(toscaGetFunction.getPropertyPathFromSource().get(0))) - .findAny() - .ifPresent(attribute -> - toscaGetFunction.setPropertyUniqueId(attribute.getUniqueId()) - ); + if (isGetPropertyOrPropertyIdNotSetAndComponentHasProperties(toscaGetFunction, selfComponent)) { + setPropertyIdFromProperty(selfComponent, toscaGetFunction); + } + } else if (toscaGetFunction.getPropertySource() == PropertySource.INSTANCE && CollectionUtils.isNotEmpty(selfComponent.getComponentInstances())) { + setSourceIdFromInstance(selfComponent, toscaGetFunction); + if (toscaGetFunction.getType() == ToscaFunctionType.GET_ATTRIBUTE) { + setPropertyIdFromInstanceAttribute(instanceAttributeMap, toscaGetFunction); } + if (toscaGetFunction.getType() == ToscaFunctionType.GET_PROPERTY || StringUtils.isEmpty(toscaGetFunction.getPropertyUniqueId())) { + setPropertyIdFromInstanceProperty(instancePropertyMap, toscaGetFunction); + } + } + } + + private boolean isGetAttributeAndComponentHasAttributes(final ToscaGetFunctionDataDefinition toscaGetFunction, final Component component) { + return toscaGetFunction.getType() == ToscaFunctionType.GET_ATTRIBUTE && CollectionUtils.isNotEmpty(component.getAttributes()); + } + + private boolean isGetPropertyOrPropertyIdNotSetAndComponentHasProperties(final ToscaGetFunctionDataDefinition toscaGetFunction, final Component component) { + return (toscaGetFunction.getType() == ToscaFunctionType.GET_PROPERTY || StringUtils.isEmpty(toscaGetFunction.getPropertyUniqueId())) && CollectionUtils.isNotEmpty(component.getProperties()); + } + + private void setPropertyIdFromAttribute(final Component component, final ToscaGetFunctionDataDefinition toscaGetFunction) { + component.getAttributes().stream() + .filter(attribute -> attribute.getName().equals(toscaGetFunction.getPropertyPathFromSource().get(0))) + .findAny() + .ifPresent(attribute -> toscaGetFunction.setPropertyUniqueId(attribute.getUniqueId())); + } + + private void setPropertyIdFromProperty(final Component component, final ToscaGetFunctionDataDefinition toscaGetFunction) { + component.getProperties().stream() + .filter(property -> property.getName().equals(toscaGetFunction.getPropertyPathFromSource().get(0))) + .findAny() + .ifPresent(property -> + toscaGetFunction.setPropertyUniqueId(property.getUniqueId()) + ); + } + + private void setSourceIdFromInstance(final Component component, final ToscaGetFunctionDataDefinition toscaGetFunction) { + component.getComponentInstances().stream() + .filter(componentInstance -> toscaGetFunction.getSourceName().equals(componentInstance.getName())) + .findAny() + .ifPresent(componentInstance -> toscaGetFunction.setSourceUniqueId(componentInstance.getUniqueId())); + } + + private void setPropertyIdFromInstanceAttribute(final Map> instanceAttributeMap, final ToscaGetFunctionDataDefinition toscaGetFunction) { + final List instanceAttributes = instanceAttributeMap.get(toscaGetFunction.getSourceUniqueId()); + if (CollectionUtils.isNotEmpty(instanceAttributes)) { + instanceAttributes.stream() + .filter(attribute -> attribute.getName().equals(toscaGetFunction.getPropertyPathFromSource().get(0))) + .findAny() + .ifPresent(attribute -> + toscaGetFunction.setPropertyUniqueId(attribute.getUniqueId()) + ); + } + } + + private void setPropertyIdFromInstanceProperty(final Map> instancePropertyMap, final ToscaGetFunctionDataDefinition toscaGetFunction) { + final List instanceProperties = instancePropertyMap.get(toscaGetFunction.getSourceUniqueId()); + if (CollectionUtils.isNotEmpty(instanceProperties)) { + instanceProperties.stream() + .filter(property -> property.getName().equals(toscaGetFunction.getPropertyPathFromSource().get(0))) + .findAny() + .ifPresent(property -> + toscaGetFunction.setPropertyUniqueId(property.getUniqueId()) + ); } } -- cgit 1.2.3-korg