diff options
author | ojasdubey <ojas.dubey@amdocs.com> | 2019-01-28 21:47:09 +0530 |
---|---|---|
committer | ojasdubey <ojas.dubey@amdocs.com> | 2019-01-29 13:19:58 +0530 |
commit | 9c0aa250313380895e9543e7e6fe83b9daf3849e (patch) | |
tree | e4a6f852e7585aa8df6b47b83769112cebbaf7a8 /catalog-be/src/main | |
parent | c0693cd275a0d35ab7acefd2ea2a936179041f41 (diff) |
Operation Outputs - Operation screen BE
1. Added implementation for using operation
outputs as mapping to input from create/update
operation screen
2. Handled populating the mapped outputs to
Tosca
3. Unit tests
Change-Id: I3d4761b07be0d4e363ff84710e92438e694a3b07
Issue-ID: SDC-2085
Signed-off-by: ojasdubey <ojas.dubey@amdocs.com>
Diffstat (limited to 'catalog-be/src/main')
4 files changed, 347 insertions, 98 deletions
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/utils/InterfaceOperationUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/utils/InterfaceOperationUtils.java index 0233711a89..6615e9ef37 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/utils/InterfaceOperationUtils.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/utils/InterfaceOperationUtils.java @@ -16,10 +16,15 @@ package org.openecomp.sdc.be.components.utils; +import java.util.List; import java.util.Map; import java.util.Optional; + +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; +import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.InputDefinition; import org.openecomp.sdc.be.model.InterfaceDefinition; import org.openecomp.sdc.be.model.Operation; @@ -61,4 +66,16 @@ public class InterfaceOperationUtils { .filter(entry -> entry.getValue().getUniqueId().equals(operationId)).findAny(); } + public static boolean isOperationInputMappedToComponentProperty(OperationInputDefinition input, + List<InputDefinition> inputs) { + if (CollectionUtils.isEmpty(inputs)) { + return false; + } + return inputs.stream().anyMatch(inp -> inp.getUniqueId().equals(input.getInputId())) + || (input.getInputId().contains(".") + && inputs.stream().anyMatch(inp -> inp.getUniqueId().equals( + input.getInputId().substring(0, input.getInputId().lastIndexOf('.'))))) ; + } + + } 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 c80f57486d..d17762fc90 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 @@ -16,7 +16,11 @@ package org.openecomp.sdc.be.components.validation; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.isOperationInputMappedToComponentProperty; + +import com.google.common.collect.Sets; import fj.data.Either; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -26,13 +30,17 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import org.openecomp.sdc.be.components.impl.ResponseFormatManager; import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; -import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.datatypes.elements.OperationOutputDefinition; import org.openecomp.sdc.be.model.InterfaceDefinition; import org.openecomp.sdc.be.model.Operation; import org.openecomp.sdc.exception.ResponseFormat; @@ -47,9 +55,10 @@ public class InterfaceOperationValidation { private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceOperationValidation.class); - public Either<Boolean, ResponseFormat> validateInterfaceOperations(InterfaceDefinition inputInterfaceDefinition, - org.openecomp.sdc.be.model.Component component, InterfaceDefinition storedInterfaceDefinition, - Map<String, InterfaceDefinition> globalInterfaceTypes, boolean isUpdate) { + public Either<Boolean, ResponseFormat> validateInterfaceOperations( + InterfaceDefinition inputInterfaceDefinition, org.openecomp.sdc.be.model.Component component, + InterfaceDefinition storedInterfaceDefinition, Map<String, InterfaceDefinition> globalInterfaceTypes, + boolean isUpdate) { Either<Boolean, ResponseFormat> validateAllowedOperationCountOnLocalInterfaceType = validateAllowedOperationCountOnLocalInterfaceType(inputInterfaceDefinition, storedInterfaceDefinition, @@ -71,8 +80,8 @@ public class InterfaceOperationValidation { } for (Operation interfaceOperation : inputInterfaceDefinition.getOperationsMap().values()) { - Either<Boolean, ResponseFormat> interfaceOperationValidatorResponse = - validateInterfaceOperation(interfaceOperation, storedInterfaceDefinition, component, isUpdate); + Either<Boolean, ResponseFormat> interfaceOperationValidatorResponse = validateInterfaceOperation( + interfaceOperation, storedInterfaceDefinition, inputInterfaceDefinition, component, isUpdate); if (interfaceOperationValidatorResponse.isRight()) { return interfaceOperationValidatorResponse; } @@ -87,15 +96,13 @@ public class InterfaceOperationValidation { boolean isInterfaceTypeExistInGlobalType = globalInterfaceTypes.values().stream().map(InterfaceDefinition::getType) - .anyMatch(type -> type.equalsIgnoreCase(inputInterfaceDefinition.getType())); - if (!isInterfaceTypeExistInGlobalType - && (inputInterfaceDefinition.getOperations().size() > 1 - || (!isUpdate && storedInterfaceDefinition != null - && storedInterfaceDefinition.getType() - .equalsIgnoreCase(inputInterfaceDefinition.getType())))) { + .anyMatch(type -> type.equalsIgnoreCase(inputInterfaceDefinition.getType())); + if (!isInterfaceTypeExistInGlobalType && (inputInterfaceDefinition.getOperations().size() > 1 + || (!isUpdate && storedInterfaceDefinition != null + && storedInterfaceDefinition.getType().equalsIgnoreCase(inputInterfaceDefinition.getType())))) { return Either.right(getResponseFormatManager() - .getResponseFormat(ActionStatus.INTERFACE_OPERATION_INVALID_FOR_LOCAL_TYPE, - inputInterfaceDefinition.getType())); + .getResponseFormat(ActionStatus.INTERFACE_OPERATION_INVALID_FOR_LOCAL_TYPE, + inputInterfaceDefinition.getType())); } return Either.left(Boolean.TRUE); @@ -105,22 +112,17 @@ public class InterfaceOperationValidation { InterfaceDefinition interfaceDefinition, Map<String, InterfaceDefinition> globalInterfaceTypes) { if (globalInterfaceTypes != null) { - boolean isOperationValidOnGlobalInterfaceType = - Stream.of(interfaceDefinition) - .filter(interfaceDef -> globalInterfaceTypes.values().stream().anyMatch( - interfaceDef1 -> interfaceDef1.getType().equalsIgnoreCase(interfaceDef.getType()))) - .flatMap(interfaceDef -> interfaceDef.getOperationsMap().values().stream() - .map(Operation::getName)) - .allMatch(operationName -> globalInterfaceTypes.values().stream() - .flatMap(interfaceDef -> interfaceDef.getOperationsMap() - .keySet().stream()) - .anyMatch(opName -> - opName.equalsIgnoreCase( - operationName))); + boolean isOperationValidOnGlobalInterfaceType = Stream.of(interfaceDefinition) + .filter(interfaceDef -> globalInterfaceTypes.values().stream().anyMatch(interfaceDef1 -> + interfaceDef1.getType().equalsIgnoreCase(interfaceDef.getType()))) + .flatMap(interfaceDef -> interfaceDef.getOperationsMap().values().stream().map(Operation::getName)) + .allMatch(operationName -> globalInterfaceTypes.values().stream() + .flatMap(interfaceDef -> interfaceDef.getOperationsMap().keySet().stream()) + .anyMatch(opName -> opName.equalsIgnoreCase(operationName))); if (!isOperationValidOnGlobalInterfaceType) { return Either.right(getResponseFormatManager() - .getResponseFormat(ActionStatus.INTERFACE_OPERATION_INVALID_FOR_GLOBAL_TYPE, - interfaceDefinition.getType())); + .getResponseFormat(ActionStatus.INTERFACE_OPERATION_INVALID_FOR_GLOBAL_TYPE, + interfaceDefinition.getType())); } } return Either.left(Boolean.TRUE); @@ -140,16 +142,19 @@ public class InterfaceOperationValidation { } private Either<Boolean, ResponseFormat> validateInterfaceOperation(Operation interfaceOperation, - InterfaceDefinition interfaceDefinition, org.openecomp.sdc.be.model.Component component, boolean isUpdate) { + InterfaceDefinition storedInterfaceDefinition, InterfaceDefinition inputInterfaceDefinition, + org.openecomp.sdc.be.model.Component component, boolean isUpdate) { ResponseFormatManager responseFormatManager = getResponseFormatManager(); Either<Boolean, ResponseFormat> interfaceOperationTypeResponse = - isInterfaceOperationTypeValid(interfaceOperation, responseFormatManager, interfaceDefinition, isUpdate); + isInterfaceOperationTypeValid(interfaceOperation, responseFormatManager, storedInterfaceDefinition, + isUpdate); if (interfaceOperationTypeResponse.isRight()) { return Either.right(interfaceOperationTypeResponse.right().value()); } - if (null != interfaceOperation.getInputs()) { + if (null != interfaceOperation.getInputs() + && CollectionUtils.isNotEmpty(interfaceOperation.getInputs().getListToscaDataDefinition())) { Either<Boolean, ResponseFormat> inputParametersResponse = validateInputParameters(interfaceOperation, responseFormatManager); if (inputParametersResponse.isRight()) { @@ -157,14 +162,15 @@ public class InterfaceOperationValidation { } Either<Boolean, ResponseFormat> inputPropertyExistInComponent = - validateInputPropertyExistInComponent(interfaceOperation, component, responseFormatManager); + validateInputPropertyExistInComponent(interfaceOperation, + inputInterfaceDefinition, component, responseFormatManager); if (inputPropertyExistInComponent.isRight()) { return Either.right(inputPropertyExistInComponent.right().value()); - } } - if (null != interfaceOperation.getOutputs()) { + if (null != interfaceOperation.getOutputs() + && CollectionUtils.isNotEmpty(interfaceOperation.getOutputs().getListToscaDataDefinition())) { Either<Boolean, ResponseFormat> outputParametersResponse = validateOutputParameters(interfaceOperation, responseFormatManager); if (outputParametersResponse.isRight()) { @@ -172,15 +178,81 @@ public class InterfaceOperationValidation { } } + if (MapUtils.isNotEmpty(component.getInterfaces()) && isUpdate) { + Either<Boolean, ResponseFormat> mappedOutputDeletedResponse = + validateMappedOutputNotDeleted(interfaceOperation, component, inputInterfaceDefinition, + responseFormatManager); + if (mappedOutputDeletedResponse.isRight()) { + return Either.right(mappedOutputDeletedResponse.right().value()); + } + } + return Either.left(Boolean.TRUE); } + + private Either<Boolean, ResponseFormat> validateMappedOutputNotDeleted(Operation interfaceOperation, + org.openecomp.sdc.be.model.Component component, InterfaceDefinition interfaceDefinition, + ResponseFormatManager responseFormatManager) { + + List<OperationOutputDefinition> existingOperationOutputs = + getInterfaceOperationOutputs(interfaceOperation.getUniqueId(), component.getInterfaces()); + if (existingOperationOutputs.isEmpty()) { + return Either.left(Boolean.TRUE); + } + Set<String> existingOperationOutputNames = existingOperationOutputs.stream() + .map(OperationOutputDefinition::getName) + .collect(Collectors.toSet()); + + ListDataDefinition<OperationOutputDefinition> currentOutputs = interfaceOperation.getOutputs(); + Set<String> currentOperationOutputNames = new HashSet<>(); + if (currentOutputs != null && !currentOutputs.isEmpty()) { + currentOperationOutputNames = currentOutputs.getListToscaDataDefinition().stream() + .map(OperationOutputDefinition::getName) + .collect(Collectors.toSet()); + } + String mappedOutputPrefix = interfaceDefinition.getType() + "." + interfaceOperation.getName(); + Set<String> deletedOutputs = Sets.difference(existingOperationOutputNames, currentOperationOutputNames); + Set<String> deletedMappedOutputs = deletedOutputs.stream() + .filter(deletedOutputName -> isMappedOutputDeleted(mappedOutputPrefix, deletedOutputName, + component.getInterfaces())) + .map(this::getOperationOutputName) + .collect(Collectors.toSet()); + + if (CollectionUtils.isNotEmpty(deletedMappedOutputs)) { + return getMappedOutputErrorResponse(responseFormatManager, deletedMappedOutputs); + } + return Either.left(Boolean.TRUE); + } + + private boolean isMappedOutputDeleted(String mappedOutputPrefix, String outputName, + Map<String, InterfaceDefinition> componentInterfaces) { + List<OperationInputDefinition> interfaceOperationInputs = + getOtherOperationInputsOfComponent(mappedOutputPrefix, componentInterfaces); + return interfaceOperationInputs.stream() + .anyMatch(operationInputDefinition -> operationInputDefinition.getInputId() + .equals(mappedOutputPrefix + "." + outputName)); + } + + 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); + ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus + .INTERFACE_OPERATION_MAPPED_OUTPUT_DELETED, deletedOutputNameList); + return Either.right(errorResponse); + } + + protected ResponseFormatManager getResponseFormatManager() { return ResponseFormatManager.getInstance(); } private Either<Boolean, ResponseFormat> isInterfaceOperationTypeValid(Operation interfaceOperation, - ResponseFormatManager responseFormatManager, InterfaceDefinition interfaceDefinition, boolean isUpdate) { + ResponseFormatManager responseFormatManager, + InterfaceDefinition interfaceDefinition, + boolean isUpdate) { Either<Boolean, ResponseFormat> operationTypeEmptyEither = isOperationTypeEmpty(responseFormatManager, interfaceOperation.getName()); @@ -194,8 +266,8 @@ public class InterfaceOperationValidation { return Either.right(operationTypeRegexValidationResponse.right().value()); } - Either<Boolean, ResponseFormat> operationTypeUniqueResponse = - validateOperationTypeUnique(interfaceOperation, interfaceDefinition, isUpdate); + Either<Boolean, ResponseFormat> operationTypeUniqueResponse = validateOperationTypeUnique(interfaceOperation, + interfaceDefinition, isUpdate); if (operationTypeUniqueResponse.isRight()) { return Either.right(operationTypeUniqueResponse.right().value()); } @@ -209,7 +281,7 @@ public class InterfaceOperationValidation { } private Either<Boolean, ResponseFormat> validateInputParameters(Operation interfaceOperation, - ResponseFormatManager responseFormatManager) { + ResponseFormatManager responseFormatManager) { if (isInputParameterNameEmpty(interfaceOperation)) { LOGGER.error("Interface operation input parameter name can't be empty"); ResponseFormat inputResponse = @@ -222,38 +294,16 @@ public class InterfaceOperationValidation { if (validateInputParametersUniqueResponse.isRight()) { LOGGER.error("Interface operation input parameter names {} already in use", validateInputParametersUniqueResponse.right().value()); - ResponseFormat inputResponse = responseFormatManager.getResponseFormat( - ActionStatus.INTERFACE_OPERATION_INPUT_NAME_ALREADY_IN_USE, - validateInputParametersUniqueResponse.right().value().toString()); + ResponseFormat inputResponse = + responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_INPUT_NAME_ALREADY_IN_USE, + validateInputParametersUniqueResponse.right().value().toString()); return Either.right(inputResponse); } return Either.left(Boolean.TRUE); } - private Either<Boolean, ResponseFormat> validateInputPropertyExistInComponent(Operation operation, - org.openecomp.sdc.be.model.Component component, ResponseFormatManager responseFormatManager) { - - List<OperationInputDefinition> inputListToscaDataDefinition = - operation.getInputs().getListToscaDataDefinition(); - for (OperationInputDefinition inputDefinition : inputListToscaDataDefinition) { - if (!validateInputExistsInComponent(inputDefinition, component.getInputs())) { - String missingPropertyName = inputDefinition.getInputId().contains(".") - ? inputDefinition.getInputId().substring( - inputDefinition.getInputId().indexOf('.') + 1) - : inputDefinition.getInputId(); - LOGGER.error("Interface operation input property {} not found in component input properties", - missingPropertyName); - ResponseFormat inputResponse = responseFormatManager.getResponseFormat( - ActionStatus.INTERFACE_OPERATION_INPUT_PROPERTY_NOT_FOUND_IN_COMPONENT, missingPropertyName, - component.getComponentType().getValue()); - return Either.right(inputResponse); - } - } - return Either.left(Boolean.TRUE); - } - private Either<Boolean, ResponseFormat> validateOutputParameters(Operation interfaceOperation, - ResponseFormatManager responseFormatManager) { + ResponseFormatManager responseFormatManager) { if (isOutputParameterNameEmpty(interfaceOperation)) { LOGGER.error("Interface operation output parameter name can't be empty"); ResponseFormat inputResponse = @@ -266,9 +316,9 @@ public class InterfaceOperationValidation { if (validateOutputParametersUniqueResponse.isRight()) { LOGGER.error("Interface operation output parameter names {} already in use", validateOutputParametersUniqueResponse.right().value()); - ResponseFormat inputResponse = responseFormatManager.getResponseFormat( - ActionStatus.INTERFACE_OPERATION_OUTPUT_NAME_ALREADY_IN_USE, - validateOutputParametersUniqueResponse.right().value().toString()); + ResponseFormat inputResponse = + responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_OUTPUT_NAME_ALREADY_IN_USE, + validateOutputParametersUniqueResponse.right().value().toString()); return Either.right(inputResponse); } return Either.left(Boolean.TRUE); @@ -330,31 +380,22 @@ public class InterfaceOperationValidation { inputParam -> inputParam.getName() == null || inputParam.getName().trim().equals(StringUtils.EMPTY)); } + private Either<Boolean, Set<String>> isInputParametersUnique(Operation operationDataDefinition) { Set<String> inputParamNamesSet = new HashSet<>(); Set<String> duplicateParamNamesToReturn = new HashSet<>(); - operationDataDefinition.getInputs().getListToscaDataDefinition().forEach(inputParam -> { - if (!inputParamNamesSet.add(inputParam.getName().trim())) { - duplicateParamNamesToReturn.add(inputParam.getName().trim()); - } - }); + operationDataDefinition.getInputs().getListToscaDataDefinition() + .forEach(inputParam -> { + if (!inputParamNamesSet.add(inputParam.getName().trim())) { + duplicateParamNamesToReturn.add(inputParam.getName().trim()); + } + }); if (!duplicateParamNamesToReturn.isEmpty()) { return Either.right(duplicateParamNamesToReturn); } return Either.left(Boolean.TRUE); } - private boolean validateInputExistsInComponent(OperationInputDefinition input, List<InputDefinition> inputs) { - return inputs.stream().anyMatch(inp -> inp.getUniqueId().equals(input.getInputId())) - || (input.getInputId().contains(".") - && inputs.stream() - .anyMatch(inp -> inp.getUniqueId() - .equals(input.getInputId() - .substring(0, - input.getInputId() - .lastIndexOf('.'))))); - } - private Boolean isOutputParameterNameEmpty(Operation operationDataDefinition) { return operationDataDefinition.getOutputs().getListToscaDataDefinition().stream().anyMatch( outputParam -> outputParam.getName() == null || outputParam.getName().trim().equals(StringUtils.EMPTY)); @@ -363,17 +404,170 @@ public class InterfaceOperationValidation { private Either<Boolean, Set<String>> isOutputParametersUnique(Operation operationDataDefinition) { Set<String> outputParamNamesSet = new HashSet<>(); Set<String> duplicateParamNamesToReturn = new HashSet<>(); - operationDataDefinition.getOutputs().getListToscaDataDefinition().forEach(outputParam -> { - if (!outputParamNamesSet.add(outputParam.getName().trim())) { - duplicateParamNamesToReturn.add(outputParam.getName().trim()); - } - }); + operationDataDefinition.getOutputs().getListToscaDataDefinition() + .forEach(outputParam -> { + if (!outputParamNamesSet.add(outputParam.getName().trim())) { + duplicateParamNamesToReturn.add(outputParam.getName().trim()); + } + }); if (!duplicateParamNamesToReturn.isEmpty()) { return Either.right(duplicateParamNamesToReturn); } return Either.left(Boolean.TRUE); } + private Either<Boolean, ResponseFormat> validateInputPropertyExistInComponent(Operation operation, + InterfaceDefinition inputInterfaceDefinition, org.openecomp.sdc.be.model.Component component, + ResponseFormatManager responseFormatManager) { + + boolean isOperationInputToInputPropertyMappingValid = false; + boolean isOperationInputToOtherOperationOutputMappingValid = false; + String mappingName = ""; + List<OperationInputDefinition> inputListToscaDataDefinition = + operation.getInputs().getListToscaDataDefinition(); + for (OperationInputDefinition inputDefinition : inputListToscaDataDefinition) { + if (isOperationInputMappedToComponentProperty(inputDefinition, component.getInputs())) { + isOperationInputToInputPropertyMappingValid = true; + } else { + mappingName = inputDefinition.getInputId().contains(".") + ? inputDefinition.getInputId().substring(inputDefinition.getInputId().lastIndexOf(".") + 1) + : inputDefinition.getInputId(); + break; + } + } + if (isOperationInputToInputPropertyMappingValid) { + return Either.left(Boolean.TRUE); + } + + //Mapped property not found in the component properties.. Check in other operation output parameters of + // component (other operation => not having the same full name) + ListDataDefinition<OperationOutputDefinition> outputListDataDefinition = + getOtherOperationOutputsOfComponent(inputInterfaceDefinition.getType(), operation.getName(), component); + + List<OperationOutputDefinition> componentOutputsFromOtherOperations = + outputListDataDefinition.getListToscaDataDefinition(); + if (validateOutputExistsInComponent(mappingName, componentOutputsFromOtherOperations)) { + isOperationInputToOtherOperationOutputMappingValid = true; + } else { + //Get the output parameter display name from the full name + mappingName = getOperationOutputName(mappingName); + } + + if (!isOperationInputToOtherOperationOutputMappingValid) { + LOGGER.error("Interface operation input parameter property {} not found in component input properties or" + + " outputs of other operations.", mappingName); + ResponseFormat inputResponse = responseFormatManager + .getResponseFormat(ActionStatus.INTERFACE_OPERATION_INPUT_PROPERTY_NOT_FOUND_IN_COMPONENT, + mappingName, component.getComponentType().getValue()); + return Either.right(inputResponse); + } + return Either.left(Boolean.TRUE); + } + + private boolean validateOutputExistsInComponent(String mappedOutputName, + List<OperationOutputDefinition> outputs) { + return outputs.stream() + .anyMatch(output -> output.getName().equals(mappedOutputName)); + } + + /** + * Get the list of outputs of other operations of all the interfaces in the component. + * @param currentInterfaceName Fully qualified interface name e.g. org.test.interfaces.node.lifecycle.Abc + * @param currentOperationName Name entered on the operation screen e.g. create + * @param component VF or service + */ + + private ListDataDefinition<OperationOutputDefinition> getOtherOperationOutputsOfComponent( + String currentInterfaceName, String currentOperationName, org.openecomp.sdc.be.model.Component component) { + ListDataDefinition<OperationOutputDefinition> componentOutputs = new ListDataDefinition<>(); + Map<String, InterfaceDefinition> componentInterfaces = component.getInterfaces(); + if (MapUtils.isEmpty(componentInterfaces)) { + return componentOutputs; + } + for (Map.Entry<String, InterfaceDefinition> interfaceDefinitionEntry : componentInterfaces.entrySet()) { + String interfaceName = interfaceDefinitionEntry.getKey(); + final Map<String, OperationDataDefinition> operations = interfaceDefinitionEntry.getValue().getOperations(); + if (MapUtils.isEmpty(operations)) { + continue; + } + String actualOperationIdentifier = currentInterfaceName + "." + currentOperationName; + for (Map.Entry<String, OperationDataDefinition> operationEntry : operations.entrySet()) { + ListDataDefinition<OperationOutputDefinition> outputs = operationEntry.getValue().getOutputs(); + String expectedOperationIdentifier = interfaceName + "." + operationEntry.getKey(); + if (!actualOperationIdentifier.equals(expectedOperationIdentifier) && !outputs.isEmpty()) { + outputs.getListToscaDataDefinition().forEach(componentOutputs::add); + } + } + } + return componentOutputs; + } + + /** + * Get the input definitions of other operations of the component from current as well as other interfaces. + * @param currentOperationIdentifier Identifier for the request operation (interface_name.operation_name) + * @param componentInterfaces Interfaces of the component + */ + private List<OperationInputDefinition> getOtherOperationInputsOfComponent(String currentOperationIdentifier, + Map<String, InterfaceDefinition> + componentInterfaces) { + List<OperationInputDefinition> otherOperationInputs = new ArrayList<>(); + if (MapUtils.isEmpty(componentInterfaces)) { + return otherOperationInputs; + } + for (Map.Entry<String, InterfaceDefinition> interfaceDefinitionEntry : componentInterfaces.entrySet()) { + final Map<String, OperationDataDefinition> operations = interfaceDefinitionEntry.getValue().getOperations(); + if (MapUtils.isEmpty(operations)) { + continue; + } + for (Map.Entry<String, OperationDataDefinition> operationEntry : operations.entrySet()) { + ListDataDefinition<OperationInputDefinition> inputs = operationEntry.getValue().getInputs(); + String expectedOperationIdentifier = + interfaceDefinitionEntry.getValue().getType() + "." + operationEntry.getValue().getName(); + if (!currentOperationIdentifier.equals(expectedOperationIdentifier) && !inputs.isEmpty()) { + otherOperationInputs.addAll(inputs.getListToscaDataDefinition()); + } + } + } + return otherOperationInputs; + } + + private String getOperationOutputName(String outputName) { + return outputName.contains(".") + ? outputName.substring(outputName.lastIndexOf(".") + 1) + : outputName; + } + + /** + * Get the output of an operation in an interface. + * @param inputOperationId Unique identifier for the request operation + * @param componentInterfaces Interfaces of the component + */ + private List<OperationOutputDefinition> getInterfaceOperationOutputs(String inputOperationId, + Map<String, InterfaceDefinition> + componentInterfaces) { + List<OperationOutputDefinition> operationOutputDefinitions = new ArrayList<>(); + if (MapUtils.isEmpty(componentInterfaces)) { + return operationOutputDefinitions; + } + for (Map.Entry<String, InterfaceDefinition> interfaceDefinitionEntry : componentInterfaces.entrySet()) { + final Map<String, OperationDataDefinition> operations = interfaceDefinitionEntry.getValue().getOperations(); + if (MapUtils.isEmpty(operations)) { + continue; + } + for (Map.Entry<String, OperationDataDefinition> operationEntry : operations.entrySet()) { + String expectedOperationId = operationEntry.getValue().getUniqueId(); + if (expectedOperationId.equals(inputOperationId)) { + ListDataDefinition<OperationOutputDefinition> operationOutputs = + operationEntry.getValue().getOutputs(); + return (Objects.isNull(operationOutputs) || operationOutputs.isEmpty()) + ? operationOutputDefinitions + : operationOutputs.getListToscaDataDefinition(); + } + } + } + return operationOutputDefinitions; + } + private boolean isValidOperationType(String operationType) { return Pattern.matches(TYPE_VALIDATION_REGEX, operationType); } 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 fbef11d2e8..efed3e9f15 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 @@ -16,6 +16,8 @@ package org.openecomp.sdc.be.tosca.utils; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.isOperationInputMappedToComponentProperty; + import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; @@ -47,10 +49,12 @@ public class InterfacesOperationsToscaUtil { private static final String DEFAULT = "default"; private static final String DEFAULT_HAS_UNDERSCORE = "_default"; private static final String DOT = "."; - private static final String SELF = "SELF"; - private static final String GET_PROPERTY = "get_property"; private static final String DEFAULTP = "defaultp"; + static final String SELF = "SELF"; + static final String GET_PROPERTY = "get_property"; + static final String GET_OPERATION_OUTPUT = "get_operation_output"; + private InterfacesOperationsToscaUtil() { } @@ -127,7 +131,7 @@ public class InterfacesOperationsToscaUtil { toscaOperation.setImplementation(operationArtifactPath); } toscaOperation.setDescription(operationEntry.getValue().getDescription()); - fillToscaOperationInputs(operationEntry.getValue(), toscaOperation); + fillToscaOperationInputs(operationEntry.getValue(), toscaOperation, interfaceType, component); toscaOperations.put(operationEntry.getValue().getName(), toscaOperation); } @@ -176,7 +180,9 @@ public class InterfacesOperationsToscaUtil { } private static void fillToscaOperationInputs(OperationDataDefinition operation, - ToscaLifecycleOperationDefinition toscaOperation) { + ToscaLifecycleOperationDefinition toscaOperation, + String interfaceType, + Component component) { if (Objects.isNull(operation.getInputs()) || operation.getInputs().isEmpty()) { toscaOperation.setInputs(null); return; @@ -186,12 +192,16 @@ public class InterfacesOperationsToscaUtil { for (OperationInputDefinition input : operation.getInputs().getListToscaDataDefinition()) { ToscaProperty toscaInput = new ToscaProperty(); toscaInput.setDescription(input.getDescription()); - String mappedPropertyName = null; + String mappedPropertyName; if (Objects.nonNull(input.getInputId())) { - mappedPropertyName = input.getInputId().substring(input.getInputId().indexOf(DOT) + 1); + if (isOperationInputMappedToComponentProperty(input, component.getInputs())) { + mappedPropertyName = input.getInputId().substring(input.getInputId().indexOf(DOT) + 1); + toscaInput.setDefaultp(createMappedInputPropertyDefaultValue(mappedPropertyName)); + } else { + mappedPropertyName = input.getInputId(); + toscaInput.setDefaultp(createMappedOutputDefaultValue(mappedPropertyName, interfaceType)); + } } - toscaInput.setDefaultp(createDefaultValue(mappedPropertyName)); - toscaInput.setType(input.getType()); toscaInput.setRequired(input.isRequired()); toscaInputs.put(input.getName(), toscaInput); @@ -200,7 +210,7 @@ public class InterfacesOperationsToscaUtil { toscaOperation.setInputs(toscaInputs); } - private static Map<String, List<String>> createDefaultValue(String propertyName) { + private static Map<String, List<String>> createMappedInputPropertyDefaultValue(String propertyName) { Map<String, List<String>> getPropertyMap = new HashMap<>(); List<String> values = new ArrayList<>(); values.add(SELF); @@ -213,6 +223,27 @@ public class InterfacesOperationsToscaUtil { return getPropertyMap; } + /** + * 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) { + 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> + 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); + return getOperationOutputMap; + } + private static Map<String, Object> getObjectAsMap(Object obj) { ObjectMapper objectMapper = new ObjectMapper(); if (obj instanceof ToscaInterfaceDefinition) { diff --git a/catalog-be/src/main/resources/config/error-configuration.yaml b/catalog-be/src/main/resources/config/error-configuration.yaml index ff86aff820..315027b43e 100644 --- a/catalog-be/src/main/resources/config/error-configuration.yaml +++ b/catalog-be/src/main/resources/config/error-configuration.yaml @@ -2137,7 +2137,7 @@ errors: # %1 - Interface Operation input property name, component type INTERFACE_OPERATION_INPUT_PROPERTY_NOT_FOUND_IN_COMPONENT: { code: 404, - message: "Error: Interface operation input parameter property '%1' not found in '%2' input properties.", + message: "Error: Interface operation input parameter property '%1' not found in '%2' input properties or outputs of other operations.", messageId: "SVC4708" } #---------SVC4709----------------------------- @@ -2172,4 +2172,11 @@ errors: code: 400, message: "Error: Invalid input, only pre-defined operation names are allowed in global interface type '%1'", messageId: "SVC4713" + } +#---------SVC4714----------------------------- +# %1 - Interface Operation output name + INTERFACE_OPERATION_MAPPED_OUTPUT_DELETED: { + code: 400, + message: "Error: Cannot update name or delete interface operation output(s) '%1' mapped to an operation input", + messageId: "SVC4714" }
\ No newline at end of file |