diff options
6 files changed, 125 insertions, 38 deletions
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/InterfaceOperationValidation.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/InterfaceOperationValidation.java index d17762fc90..250fc03c21 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/InterfaceOperationValidation.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/InterfaceOperationValidation.java @@ -179,11 +179,11 @@ public class InterfaceOperationValidation { } if (MapUtils.isNotEmpty(component.getInterfaces()) && isUpdate) { - Either<Boolean, ResponseFormat> mappedOutputDeletedResponse = - validateMappedOutputNotDeleted(interfaceOperation, component, inputInterfaceDefinition, + Either<Boolean, ResponseFormat> mappedOutputModifiedResponse = + validateMappedOutputNotModified(interfaceOperation, component, inputInterfaceDefinition, responseFormatManager); - if (mappedOutputDeletedResponse.isRight()) { - return Either.right(mappedOutputDeletedResponse.right().value()); + if (mappedOutputModifiedResponse.isRight()) { + return Either.right(mappedOutputModifiedResponse.right().value()); } } @@ -191,7 +191,7 @@ public class InterfaceOperationValidation { } - private Either<Boolean, ResponseFormat> validateMappedOutputNotDeleted(Operation interfaceOperation, + private Either<Boolean, ResponseFormat> validateMappedOutputNotModified(Operation interfaceOperation, org.openecomp.sdc.be.model.Component component, InterfaceDefinition interfaceDefinition, ResponseFormatManager responseFormatManager) { @@ -222,6 +222,18 @@ public class InterfaceOperationValidation { if (CollectionUtils.isNotEmpty(deletedMappedOutputs)) { return getMappedOutputErrorResponse(responseFormatManager, deletedMappedOutputs); } + + if (currentOutputs != null && !currentOutputs.isEmpty()) { + Set<String> unchangedOutputNames = Sets.intersection(existingOperationOutputNames, + currentOperationOutputNames); + Set<String> modifiedMappedOutputNames = + getModifiedMappedOutputNames(currentOutputs.getListToscaDataDefinition(), + existingOperationOutputs, unchangedOutputNames); + if (CollectionUtils.isNotEmpty(modifiedMappedOutputNames)) { + return getMappedOutputErrorResponse(responseFormatManager, modifiedMappedOutputNames); + } + } + return Either.left(Boolean.TRUE); } @@ -234,13 +246,36 @@ public class InterfaceOperationValidation { .equals(mappedOutputPrefix + "." + outputName)); } + private static Set<String> getModifiedMappedOutputNames(List<OperationOutputDefinition> currentOperationOutputs, + List<OperationOutputDefinition> existingOperationOutputs, + Set<String> unchangedOutputNames) { + Set<String> modifiedOutputDefinitionNames = new HashSet<>(); + Map<String, OperationOutputDefinition> newOutputMap = + currentOperationOutputs.stream().collect(Collectors.toMap(OperationOutputDefinition::getName, + (OperationOutputDefinition operationOutputDefinition) -> operationOutputDefinition)); + + Map<String, OperationOutputDefinition> existingOutputMap = + existingOperationOutputs.stream().collect(Collectors.toMap(OperationOutputDefinition::getName, + (OperationOutputDefinition operationOutputDefinition) -> operationOutputDefinition)); + + for (String outputName : unchangedOutputNames) { + OperationOutputDefinition existingOutputDefinition = existingOutputMap.get(outputName); + OperationOutputDefinition newOutputDefinition = newOutputMap.get(outputName); + if (!existingOutputDefinition.getType().equals(newOutputDefinition.getType()) + || !existingOutputDefinition.isRequired().equals(newOutputDefinition.isRequired())) { + modifiedOutputDefinitionNames.add(outputName); + } + } + return modifiedOutputDefinitionNames; + } + private Either<Boolean, ResponseFormat> getMappedOutputErrorResponse(ResponseFormatManager responseFormatManager, - Set<String> deletedMappedOutputs) { - String deletedOutputNameList = String.join(",", deletedMappedOutputs); - LOGGER.error("Cannot update name or delete interface operation output(s) '{}' mapped to an operation input", - deletedOutputNameList); + Set<String> modifiedMappedOutputs) { + String modifiedOutputNameList = String.join(",", modifiedMappedOutputs); + LOGGER.error("Cannot update or delete interface operation output(s) '{}' mapped to an operation input", + modifiedOutputNameList); ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus - .INTERFACE_OPERATION_MAPPED_OUTPUT_DELETED, deletedOutputNameList); + .INTERFACE_OPERATION_MAPPED_OUTPUT_MODIFIED, modifiedOutputNameList); return Either.right(errorResponse); } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/utils/InterfacesOperationsToscaUtil.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/utils/InterfacesOperationsToscaUtil.java index efed3e9f15..106aa58133 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/utils/InterfacesOperationsToscaUtil.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/utils/InterfacesOperationsToscaUtil.java @@ -20,14 +20,12 @@ import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.isOp import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; - import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; - import org.apache.commons.collections.MapUtils; import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; @@ -59,7 +57,7 @@ public class InterfacesOperationsToscaUtil { } /** - * Creates the interface_types element + * Creates the interface_types element. * * @param component to work on * @return the added element @@ -99,7 +97,7 @@ public class InterfacesOperationsToscaUtil { } /** - * Adds the 'interfaces' element to the node type provided + * Adds the 'interfaces' element to the node type provided. * * @param component to work on * @param nodeType to which the interfaces element will be added @@ -131,7 +129,7 @@ public class InterfacesOperationsToscaUtil { toscaOperation.setImplementation(operationArtifactPath); } toscaOperation.setDescription(operationEntry.getValue().getDescription()); - fillToscaOperationInputs(operationEntry.getValue(), toscaOperation, interfaceType, component); + fillToscaOperationInputs(operationEntry.getValue(), toscaOperation, component); toscaOperations.put(operationEntry.getValue().getName(), toscaOperation); } @@ -148,7 +146,7 @@ public class InterfacesOperationsToscaUtil { } } - /*** + /* * workaround for : currently "defaultp" is not being converted to "default" by the relevant code in * ToscaExportHandler so, any string Map key named "defaultp" will have its named changed to "default" * @param operationsMap the map to update @@ -181,7 +179,6 @@ public class InterfacesOperationsToscaUtil { private static void fillToscaOperationInputs(OperationDataDefinition operation, ToscaLifecycleOperationDefinition toscaOperation, - String interfaceType, Component component) { if (Objects.isNull(operation.getInputs()) || operation.getInputs().isEmpty()) { toscaOperation.setInputs(null); @@ -199,7 +196,7 @@ public class InterfacesOperationsToscaUtil { toscaInput.setDefaultp(createMappedInputPropertyDefaultValue(mappedPropertyName)); } else { mappedPropertyName = input.getInputId(); - toscaInput.setDefaultp(createMappedOutputDefaultValue(mappedPropertyName, interfaceType)); + toscaInput.setDefaultp(createMappedOutputDefaultValue(mappedPropertyName)); } } toscaInput.setType(input.getType()); @@ -224,23 +221,28 @@ public class InterfacesOperationsToscaUtil { } /** - * Create the value for operation input mapped to an operation output + * Create the value for operation input mapped to an operation output. * @param propertyName the mapped other operation output full name - * @param interfaceType full interface name * @return input map for tosca */ - private static Map<String, List<String>> createMappedOutputDefaultValue(String propertyName, String interfaceType) { + private static Map<String, List<String>> createMappedOutputDefaultValue(String propertyName) { Map<String, List<String>> getOperationOutputMap = new HashMap<>(); //For operation input mapped to other operation output parameter, the mapped property value // should be of the format <interface name>.<operation name>.<output parameter name> + // Operation name and output param name should not contain "." List<String> defaultMappedOperationOutputValue = new ArrayList<>(); - defaultMappedOperationOutputValue.add(SELF); - String fullOutputPropertyName = - propertyName.substring(propertyName.indexOf(interfaceType) + interfaceType.length() + 1); - defaultMappedOperationOutputValue.add(interfaceType); - //Output name should not contain dot - defaultMappedOperationOutputValue.addAll(Arrays.asList(fullOutputPropertyName.split("\\."))); - getOperationOutputMap.put(GET_OPERATION_OUTPUT, defaultMappedOperationOutputValue); + String[] tokens = propertyName.split("\\."); + if (tokens.length > 2) { + defaultMappedOperationOutputValue.add(SELF); + String outputPropertyName = tokens[tokens.length - 1]; + String operationName = tokens[tokens.length - 2]; + String mappedPropertyInterfaceType = + propertyName.substring(0, propertyName.indexOf(operationName + '.' + outputPropertyName) - 1); + String interfaceName = + mappedPropertyInterfaceType.substring(mappedPropertyInterfaceType.lastIndexOf('.') + 1); + defaultMappedOperationOutputValue.addAll(Arrays.asList(interfaceName, operationName, outputPropertyName)); + getOperationOutputMap.put(GET_OPERATION_OUTPUT, defaultMappedOperationOutputValue); + } return getOperationOutputMap; } diff --git a/catalog-be/src/main/resources/config/error-configuration.yaml b/catalog-be/src/main/resources/config/error-configuration.yaml index 69f67e63ed..c92b0fd771 100644 --- a/catalog-be/src/main/resources/config/error-configuration.yaml +++ b/catalog-be/src/main/resources/config/error-configuration.yaml @@ -2235,10 +2235,10 @@ errors: message: "Error: Property type %1 provided against %2 is not supported for static value.", messageId: "SVC4721" } -#---------SVC4714----------------------------- +#---------SVC4723----------------------------- # %1 - Interface Operation output name - INTERFACE_OPERATION_MAPPED_OUTPUT_DELETED: { + INTERFACE_OPERATION_MAPPED_OUTPUT_MODIFIED: { code: 400, - message: "Error: Cannot update name or delete interface operation output(s) '%1' mapped to an operation input", - messageId: "SVC4714" + message: "Error: Cannot update or delete interface operation output(s) '%1' mapped to an operation input", + messageId: "SVC4723" }
\ No newline at end of file diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/utils/InterfacesOperationsToscaUtilTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/utils/InterfacesOperationsToscaUtilTest.java index 36dd5d9796..156d280a6e 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/utils/InterfacesOperationsToscaUtilTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/utils/InterfacesOperationsToscaUtilTest.java @@ -24,13 +24,11 @@ import static org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.add import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; - import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -236,6 +234,54 @@ public class InterfacesOperationsToscaUtilTest { validateOperationInputs(mainYaml, 2, "name_for_op_1"); } + @Test + public void addInterfaceDefinitionElementInputMappedToOtherOperationOutputFromOtherInterface() { + String addedInterfaceType = "com.some.resource.or.other.resourceNameInputMappedToOutput"; + Component component = new Resource(); + component.setNormalizedName("normalizedComponentName"); + InterfaceDefinition addedInterface = new InterfaceDefinition(); + addedInterface.setType(addedInterfaceType); + addOperationsToInterface(component, addedInterface, 2, 2, true, true); + addedInterface.getOperationsMap().values().stream() + .filter(operationInputDefinition -> operationInputDefinition.getName().equalsIgnoreCase( + "name_for_op_0")) + .forEach(operation -> operation.getInputs().getListToscaDataDefinition().stream() + .filter(opInputDef -> opInputDef.getName().contains("integer")) + .forEach(opInputDef -> opInputDef.setInputId( + addedInterfaceType +".name_for_op_1.output_integer_1"))); + //Mapping to operation from another interface + String secondInterfaceType = "org.test.lifecycle.standard.interfaceType.second"; + InterfaceDefinition secondInterface = new InterfaceDefinition(); + secondInterface.setType(secondInterfaceType); + addOperationsToInterface(component, secondInterface, 2, 2, true, true); + secondInterface.getOperationsMap().values().stream() + .filter(operationInputDefinition -> operationInputDefinition.getName().equalsIgnoreCase( + "name_for_op_0")) + .forEach(operation -> operation.getInputs().getListToscaDataDefinition().stream() + .filter(opInputDef -> opInputDef.getName().contains("integer")) + .forEach(opInputDef -> opInputDef.setInputId( + addedInterfaceType +".name_for_op_1.output_integer_1"))); + component.setInterfaces(new HashMap<>()); + component.getInterfaces().put(addedInterfaceType, addedInterface); + component.getInterfaces().put(secondInterfaceType, secondInterface); + + ToscaNodeType nodeType = new ToscaNodeType(); + addInterfaceDefinitionElement(component, nodeType, false); + + ToscaExportHandler handler = new ToscaExportHandler(null,null,null,null,null,null, null); + ToscaTemplate template = new ToscaTemplate("test"); + Map<String, ToscaNodeType> nodeTypes = new HashMap<>(); + nodeTypes.put("test", nodeType); + template.setNode_types(nodeTypes); + final ToscaRepresentation toscaRepresentation = handler.createToscaRepresentation(template); + + String mainYaml = toscaRepresentation.getMainYaml(); + Assert.assertFalse(mainYaml.contains("operations")); + Assert.assertTrue(mainYaml.contains("resourceNameInputMappedToOutput:")); + Assert.assertTrue(mainYaml.contains("inputs:")); + validateOperationInputs(mainYaml, 2, "name_for_op_1"); + } + private void addOperationsToInterface(Component component, InterfaceDefinition addedInterface, int numOfOps, int numOfInputsPerOp, boolean hasInputs, boolean hasOutputs) { @@ -319,7 +365,8 @@ public class InterfacesOperationsToscaUtilTest { for (Map.Entry<String, Object> operationEntry : interfaceDefinition.entrySet()) { Object operationVal = operationEntry.getValue(); if (operationVal instanceof Map) { - validateOperationInputDefinition((String) interfaceDefinition.get("type"), mappedOperationName, + //Since the inputs are mapped to output operations from only first interface so using that name + validateOperationInputDefinition(interfaces.keySet().iterator().next(), mappedOperationName, operationVal); } } diff --git a/catalog-be/src/test/java/org/openecomp/sdc/test/utils/InterfaceOperationTestUtils.java b/catalog-be/src/test/java/org/openecomp/sdc/test/utils/InterfaceOperationTestUtils.java index c614c6e6e9..1cc5b56ca9 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/test/utils/InterfaceOperationTestUtils.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/test/utils/InterfaceOperationTestUtils.java @@ -18,7 +18,6 @@ package org.openecomp.sdc.test.utils; import java.util.HashMap; import java.util.Map; - import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationOutputDefinition; @@ -87,6 +86,8 @@ public class InterfaceOperationTestUtils { operationInputDefinition.setInputId("ComponentInput" + num + "_uniqueId"); operationInputDefinition.setValue(inputName + "_value"); operationInputDefinition.setDefaultValue(inputName + "_defaultValue"); + operationInputDefinition.setType("string"); + operationInputDefinition.setRequired(true); return operationInputDefinition; } @@ -96,6 +97,8 @@ public class InterfaceOperationTestUtils { operationOutputDefinition.setUniqueId(outputName + "_uniqueId"); operationOutputDefinition.setValue(outputName + "_value"); operationOutputDefinition.setDefaultValue(outputName + "_defaultValue"); + operationOutputDefinition.setType("string"); + operationOutputDefinition.setRequired(true); return operationOutputDefinition; } diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java index 8715e1d9c6..33515c3d78 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java @@ -124,7 +124,7 @@ public enum ActionStatus { INTERFACE_OPERATION_NOT_FOUND, INTERFACE_OPERATION_NAME_ALREADY_IN_USE, INTERFACE_OPERATION_NAME_MANDATORY, INTERFACE_OPERATION_NAME_INVALID, INTERFACE_OPERATION_INPUT_NAME_ALREADY_IN_USE, INTERFACE_OPERATION_OUTPUT_NAME_ALREADY_IN_USE, INTERFACE_OPERATION_NOT_DELETED, - INTERFACE_OPERATION_MAPPED_OUTPUT_DELETED, + INTERFACE_OPERATION_MAPPED_OUTPUT_MODIFIED, INTERFACE_OPERATION_INPUT_NAME_MANDATORY, INTERFACE_OPERATION_OUTPUT_NAME_MANDATORY, INTERFACE_OPERATION_INPUT_PROPERTY_NOT_FOUND_IN_COMPONENT, INTERFACE_OPERATION_INVALID_FOR_LOCAL_TYPE, INTERFACE_OPERATION_INVALID_FOR_GLOBAL_TYPE, @@ -142,5 +142,5 @@ public enum ActionStatus { //InterfaceLifeCycleType - INTERFACE_LIFECYCLE_TYPES_NOT_FOUND; + INTERFACE_LIFECYCLE_TYPES_NOT_FOUND } |