diff options
author | ojasdubey <ojas.dubey@amdocs.com> | 2019-03-18 11:55:56 +0530 |
---|---|---|
committer | ojasdubey <ojas.dubey@amdocs.com> | 2019-03-18 12:18:42 +0530 |
commit | 2ca2fc5c0da1eb862fcd79d1f9345aa89e62b396 (patch) | |
tree | 15d2cf2c7d6e9024430f735addf9e947d2814830 /catalog-be/src/main | |
parent | 532b6da80ebd6977aa27300ab3cbe7b21d88609a (diff) |
Service Consumption BE
1. Service consumption feature
backend implementation
2. Operation output bug fix for
delete operation not allowed for
mapped operation output
Change-Id: Ib2554eed4f940b003955263a0c8bf795a23cac9a
Issue-ID: SDC-1990
Signed-off-by: ojasdubey <ojas.dubey@amdocs.com>
Diffstat (limited to 'catalog-be/src/main')
20 files changed, 1412 insertions, 275 deletions
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 dfdae9be5e..d9a0c46fa9 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 @@ -332,6 +332,9 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { resourceInstance.setProperties(ProxyServicePropertiesUtils.getProperties(service)); + List<InputDefinition> serviceInputs = service.getInputs(); + resourceInstance.setInputs(serviceInputs); + String name = service.getNormalizedName() + ToscaOperationFacade.PROXY_SUFFIX; String toscaResourceName = ((Resource) proxyTemplate).getToscaResourceName(); int lastIndexOf = toscaResourceName.lastIndexOf('.'); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java index 8a111f359e..357eb14ed0 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java @@ -20,6 +20,13 @@ package org.openecomp.sdc.be.components.impl; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + import fj.data.Either; import org.openecomp.sdc.be.components.property.PropertyDeclarationOrchestrator; import org.openecomp.sdc.be.components.validation.ComponentValidations; @@ -30,7 +37,13 @@ import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition; -import org.openecomp.sdc.be.model.*; +import org.openecomp.sdc.be.model.ComponentInstInputsMap; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceInput; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.InputDefinition; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; @@ -40,8 +53,6 @@ import org.openecomp.sdc.exception.ResponseFormat; import org.springframework.stereotype.Component; import javax.inject.Inject; -import java.util.*; -import java.util.stream.Collectors; @Component("inputsBusinessLogic") public class InputsBusinessLogic extends BaseBusinessLogic { @@ -279,6 +290,7 @@ public class InputsBusinessLogic extends BaseBusinessLogic { return Either.right(updateInputObjectValue.right().value()); } String newValue = updateInputObjectValue.left().value(); + currInput.setValue(newValue); currInput.setDefaultValue(newValue); currInput.setOwnerId(userId); Either<InputDefinition, StorageOperationStatus> status = toscaOperationFacade.updateInputOfComponent(component, currInput); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceOperationBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceOperationBusinessLogic.java index 2fb7b0f09e..71d79e0410 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceOperationBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceOperationBusinessLogic.java @@ -17,9 +17,17 @@ package org.openecomp.sdc.be.components.impl; -import fj.data.Either; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.createMappedInputPropertyDefaultValue; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.createMappedOutputDefaultValue; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.getInterfaceDefinitionFromComponentByInterfaceId; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.getInterfaceDefinitionFromComponentByInterfaceType; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.getOperationFromInterfaceDefinition; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.isOperationInputMappedToComponentInput; +import static org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.SELF; + +import com.google.gson.Gson; + import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -29,14 +37,21 @@ import java.util.Objects; import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; -import org.openecomp.sdc.be.components.utils.InterfaceOperationUtils; + +import fj.data.Either; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; import org.openecomp.sdc.be.components.validation.InterfaceOperationValidation; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.cassandra.ArtifactCassandraDao; import org.openecomp.sdc.be.dao.cassandra.CassandraOperationStatus; +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.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.ComponentInstanceInterface; +import org.openecomp.sdc.be.model.InputDefinition; import org.openecomp.sdc.be.model.InterfaceDefinition; import org.openecomp.sdc.be.model.Operation; import org.openecomp.sdc.be.model.User; @@ -83,9 +98,8 @@ public class InterfaceOperationBusinessLogic extends BaseBusinessLogic { } try { - Optional<InterfaceDefinition> optionalInterface = InterfaceOperationUtils - .getInterfaceDefinitionFromComponentByInterfaceId( - storedComponent, interfaceId); + Optional<InterfaceDefinition> optionalInterface = getInterfaceDefinitionFromComponentByInterfaceId( + storedComponent, interfaceId); if (!optionalInterface.isPresent()) { return Either.right( componentsUtils.getResponseFormat(ActionStatus.INTERFACE_NOT_FOUND_IN_COMPONENT, interfaceId)); @@ -95,13 +109,19 @@ public class InterfaceOperationBusinessLogic extends BaseBusinessLogic { Map<String, Operation> operationsCollection = new HashMap<>(); for (String operationId : operationsToDelete) { Optional<Map.Entry<String, Operation>> optionalOperation = - InterfaceOperationUtils.getOperationFromInterfaceDefinition(interfaceDefinition, operationId); + getOperationFromInterfaceDefinition(interfaceDefinition, operationId); if (!optionalOperation.isPresent()) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND, storedComponent.getUniqueId())); } Operation storedOperation = optionalOperation.get().getValue(); + Either<Boolean, ResponseFormat> validateDeleteOperationContainsNoMappedOutputResponse = + interfaceOperationValidation.validateDeleteOperationContainsNoMappedOutput(storedOperation, + storedComponent, interfaceDefinition); + if (validateDeleteOperationContainsNoMappedOutputResponse.isRight()) { + return Either.right(validateDeleteOperationContainsNoMappedOutputResponse.right().value()); + } String artifactUuId = storedOperation.getImplementation().getArtifactUUID(); CassandraOperationStatus cassandraStatus = artifactCassandraDao.deleteArtifact(artifactUuId); if (cassandraStatus != CassandraOperationStatus.OK) { @@ -190,9 +210,8 @@ public class InterfaceOperationBusinessLogic extends BaseBusinessLogic { } try { - Optional<InterfaceDefinition> optionalInterface = InterfaceOperationUtils - .getInterfaceDefinitionFromComponentByInterfaceId( - storedComponent, interfaceId); + Optional<InterfaceDefinition> optionalInterface = getInterfaceDefinitionFromComponentByInterfaceId( + storedComponent, interfaceId); if (!optionalInterface.isPresent()) { return Either.right( componentsUtils.getResponseFormat(ActionStatus.INTERFACE_NOT_FOUND_IN_COMPONENT, interfaceId)); @@ -201,7 +220,7 @@ public class InterfaceOperationBusinessLogic extends BaseBusinessLogic { for (String operationId : operationsToGet) { Optional<Map.Entry<String, Operation>> optionalOperation = - InterfaceOperationUtils.getOperationFromInterfaceDefinition(interfaceDefinition, operationId); + getOperationFromInterfaceDefinition(interfaceDefinition, operationId); if (!optionalOperation.isPresent()) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND, storedComponent.getUniqueId())); @@ -257,7 +276,7 @@ public class InterfaceOperationBusinessLogic extends BaseBusinessLogic { Map<String, Operation> operationsCollection = new HashMap<>(); for (InterfaceDefinition inputInterfaceDefinition : interfaceDefinitions) { Optional<InterfaceDefinition> optionalInterface = - InterfaceOperationUtils.getInterfaceDefinitionFromComponentByInterfaceType( + getInterfaceDefinitionFromComponentByInterfaceType( storedComponent, inputInterfaceDefinition.getType()); Either<Boolean, ResponseFormat> interfaceOperationValidationResponseEither = interfaceOperationValidation @@ -287,7 +306,7 @@ public class InterfaceOperationBusinessLogic extends BaseBusinessLogic { addOperationToInterface(interfaceDef, operation); } else { Optional<Map.Entry<String, Operation>> optionalOperation = - InterfaceOperationUtils.getOperationFromInterfaceDefinition(interfaceDef, + getOperationFromInterfaceDefinition(interfaceDef, operation.getUniqueId()); if (!optionalOperation.isPresent()) { titanDao.rollback(); @@ -364,31 +383,53 @@ public class InterfaceOperationBusinessLogic extends BaseBusinessLogic { InterfaceDefinition storedInterfaceDef) { if (storedInterfaceDef != null) { return Either.left(storedInterfaceDef); - } else { - interfaceDefinition.setUniqueId(UUID.randomUUID().toString()); - interfaceDefinition.setToscaResourceName(interfaceDefinition.getType()); - Either<List<InterfaceDefinition>, StorageOperationStatus> interfaceCreateEither = - interfaceOperation.addInterfaces(component.getUniqueId(), - Collections.singletonList(interfaceDefinition)); - if (interfaceCreateEither.isRight()) { - titanDao.rollback(); - return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse( - interfaceCreateEither.right().value(), component.getComponentType()))); - } - return Either.left(interfaceCreateEither.left().value().get(0)); } + interfaceDefinition.setUniqueId(UUID.randomUUID().toString()); + interfaceDefinition.setToscaResourceName(interfaceDefinition.getType()); + Either<List<InterfaceDefinition>, StorageOperationStatus> interfaceCreateEither = + interfaceOperation.addInterfaces(component.getUniqueId(), + Collections.singletonList(interfaceDefinition)); + if (interfaceCreateEither.isRight()) { + titanDao.rollback(); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse( + interfaceCreateEither.right().value(), component.getComponentType()))); + } + return Either.left(interfaceCreateEither.left().value().get(0)); } private void updateOperationInputDefs(org.openecomp.sdc.be.model.Component component, - Collection<Operation> interfaceOperations) { + Collection<Operation> interfaceOperations) { interfaceOperations.stream().filter(operation -> Objects.nonNull(operation.getInputs())).forEach( operation -> operation.getInputs().getListToscaDataDefinition().forEach( - inp -> component.getInputs().stream().filter(in -> inp.getInputId().equals(in.getUniqueId())) - .forEach(in -> { - inp.setDefaultValue(in.getDefaultValue()); - inp.setValue(in.getValue()); - inp.setSchema(in.getSchema()); - }))); + inp -> component.getInputs() + .forEach(in -> updateOperationInputDefinition(component, inp, in)))); + } + + private void updateOperationInputDefinition(org.openecomp.sdc.be.model.Component component, + OperationInputDefinition operationInput, + InputDefinition componentInput) { + if (operationInput.getInputId().equals(componentInput.getUniqueId())) { + //Set the default value, value and schema only for inputs mapped to component inputs + operationInput.setDefaultValue(componentInput.getDefaultValue()); + operationInput.setToscaDefaultValue(getInputToscaDefaultValue(operationInput, component)); + operationInput.setValue(componentInput.getValue()); + operationInput.setSchema(componentInput.getSchema()); + } + //Set the tosca default value for inputs mapped to component inputs as well as other outputs + operationInput.setToscaDefaultValue(getInputToscaDefaultValue(operationInput, component)); + } + + private String getInputToscaDefaultValue(OperationInputDefinition input, + org.openecomp.sdc.be.model.Component component) { + Map<String, List<String>> defaultInputValue; + if (isOperationInputMappedToComponentInput(input, component.getInputs())) { + String propertyName = input.getInputId().substring(input.getInputId().indexOf('.') + 1); + defaultInputValue = createMappedInputPropertyDefaultValue(propertyName); + } else { + //Currently inputs can only be mapped to a declared input or an other operation outputs + defaultInputValue = createMappedOutputDefaultValue(SELF, input.getInputId()); + } + return new Gson().toJson(defaultInputValue); } private void addOperationToInterface(InterfaceDefinition interfaceDefinition, Operation interfaceOperation) { @@ -420,4 +461,55 @@ public class InterfaceOperationBusinessLogic extends BaseBusinessLogic { UPDATE_INTERFACE_OPERATION, lock); } + public Either<List<OperationInputDefinition>, ResponseFormat> getInputsListForOperation(String componentId, + String componentInstanceId, String interfaceId, String operationId, User user) { + Either<org.openecomp.sdc.be.model.Component, ResponseFormat> componentEither = getComponentDetails(componentId); + if (componentEither.isRight()){ + return Either.right(componentEither.right().value()); + } + + org.openecomp.sdc.be.model.Component storedComponent = componentEither.left().value(); + validateUserExists(user.getUserId(), GET_INTERFACE_OPERATION, true); + + Either<Boolean, ResponseFormat> lockResult = lockComponentResult(true, storedComponent, GET_INTERFACE_OPERATION); + if (lockResult.isRight()) { + return Either.right(lockResult.right().value()); + } + + try{ + org.openecomp.sdc.be.model.Component parentComponent = componentEither.left().value(); + Map<String, List<ComponentInstanceInterface>> componentInstanceInterfaces = + parentComponent.getComponentInstancesInterfaces(); + if(MapUtils.isEmpty(componentInstanceInterfaces)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND, + componentInstanceId)); + } + + List<ComponentInstanceInterface> componentInstanceInterfaceList = + componentInstanceInterfaces.get(componentInstanceId); + for(ComponentInstanceInterface componentInstanceInterface : componentInstanceInterfaceList) { + if(componentInstanceInterface.getInterfaceId().equals(interfaceId)){ + Map<String, OperationDataDefinition> operations = componentInstanceInterface.getOperations(); + if(MapUtils.isNotEmpty(operations) && operations.containsKey(operationId)) { + ListDataDefinition<OperationInputDefinition> inputs = operations.get(operationId).getInputs(); + return Either.left(CollectionUtils.isEmpty(inputs.getListToscaDataDefinition()) + ? new ArrayList<>() : inputs.getListToscaDataDefinition()); + } + } + } + return Either.left(new ArrayList<>()); + } + catch (Exception e) { + LOGGER.error(EXCEPTION_OCCURRED_DURING_INTERFACE_OPERATION, "get", e); + titanDao.rollback(); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND)); + } + finally { + if (lockResult.isLeft() && lockResult.left().value()) { + graphLockOperation.unlockComponent(storedComponent.getUniqueId(), + NodeTypeEnum.getByNameIgnoreCase(storedComponent.getComponentType().getValue())); + } + } + } + } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/PropertyBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/PropertyBusinessLogic.java index 0439dd5ef6..3c49e21471 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/PropertyBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/PropertyBusinessLogic.java @@ -28,10 +28,20 @@ import org.apache.commons.lang3.tuple.ImmutablePair; import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; -import org.openecomp.sdc.be.datatypes.elements.*; +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.datatypes.elements.PropertyDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.impl.WebAppContextWrapper; -import org.openecomp.sdc.be.model.*; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstanceInterface; +import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.IComplexDefaultValue; +import org.openecomp.sdc.be.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.operations.api.IElementOperation; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; @@ -377,7 +387,8 @@ public class PropertyBusinessLogic extends BaseBusinessLogic { return Optional.empty(); } - return operationInputsList.stream().filter(input -> input.getInputId().equals(propertyDefinition.getUniqueId())).findAny(); + return operationInputsList.stream().filter(input -> input.getInputId().equals(propertyDefinition.getUniqueId()) + || (input.getSourceProperty() != null && input.getSourceProperty().equals(propertyDefinition.getUniqueId()))).findAny(); } /** diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java index dfe1467a9c..65b1f12c03 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java @@ -25,6 +25,7 @@ import com.google.common.base.Strings; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import fj.data.Either; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; @@ -36,6 +37,7 @@ import org.openecomp.sdc.be.components.impl.exceptions.ComponentException; import org.openecomp.sdc.be.components.impl.utils.NodeFilterConstraintAction; import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction; import org.openecomp.sdc.be.components.path.ForwardingPathValidator; +import org.openecomp.sdc.be.components.utils.InterfaceOperationUtils; import org.openecomp.sdc.be.components.validation.NodeFilterValidator; import org.openecomp.sdc.be.components.validation.ServiceDistributionValidation; import org.openecomp.sdc.be.config.BeEcompErrorManager; @@ -47,9 +49,14 @@ import org.openecomp.sdc.be.datamodel.ServiceRelations; import org.openecomp.sdc.be.datamodel.utils.UiComponentDataConverter; import org.openecomp.sdc.be.datatypes.elements.CINodeFilterDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ForwardingPathDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.InterfaceDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; +import org.openecomp.sdc.be.datatypes.elements.OperationOutputDefinition; import org.openecomp.sdc.be.datatypes.elements.RequirementNodeFilterPropertyDataDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.InstantiationTypes; +import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; import org.openecomp.sdc.be.externalapi.servlet.representation.ServiceDistributionReqInfo; @@ -65,11 +72,16 @@ import org.openecomp.sdc.be.model.operations.api.IElementOperation; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; +import org.openecomp.sdc.be.model.tosca.ToscaFunctions; +import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; +import org.openecomp.sdc.be.model.tosca.validators.PropertyTypeValidator; import org.openecomp.sdc.be.resources.data.ComponentInstanceData; import org.openecomp.sdc.be.resources.data.ComponentMetadataData; import org.openecomp.sdc.be.resources.data.auditing.*; import org.openecomp.sdc.be.resources.data.auditing.model.ResourceCommonInfo; import org.openecomp.sdc.be.resources.data.auditing.model.ResourceVersionInfo; +import org.openecomp.sdc.be.types.ServiceConsumptionData; +import org.openecomp.sdc.be.types.ServiceConsumptionSource; import org.openecomp.sdc.be.ui.model.UiComponentDataTransfer; import org.openecomp.sdc.be.user.Role; import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; @@ -83,6 +95,7 @@ import org.openecomp.sdc.common.util.ThreadLocalsHolder; import org.openecomp.sdc.common.util.ValidationUtils; import org.openecomp.sdc.exception.ResponseFormat; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.web.context.WebApplicationContext; import javax.servlet.ServletContext; @@ -95,7 +108,12 @@ import java.util.stream.Collectors; import static org.apache.commons.collections.CollectionUtils.isEmpty; import static org.apache.commons.collections.CollectionUtils.isNotEmpty; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.getOperationOutputName; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.isOperationInputMappedToOtherOperationOutput; import static org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum.UPDATE_SERVICE_METADATA; +import static org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.SELF; +import static org.openecomp.sdc.be.types.ServiceConsumptionSource.SERVICE_INPUT; +import static org.openecomp.sdc.be.types.ServiceConsumptionSource.STATIC; @org.springframework.stereotype.Component("serviceBusinessLogic") public class ServiceBusinessLogic extends ComponentBusinessLogic { @@ -227,6 +245,441 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic { } + public Either<List<Operation>, ResponseFormat> addServiceConsumptionData(String serviceId, + String serviceInstanceId, + String operationId, + List<ServiceConsumptionData> serviceConsumptionDataList, + String userId) { + List<Operation> operationList = new ArrayList<>(); + + Either<Service, StorageOperationStatus> serviceEither = + toscaOperationFacade.getToscaElement(serviceId); + if(serviceEither.isRight()) { + return Either.right(componentsUtils.getResponseFormat + (serviceEither.right().value())); + } + + Service service = serviceEither.left().value(); + + + StorageOperationStatus storageOperationStatus = + graphLockOperation.lockComponent(service.getUniqueId(), NodeTypeEnum.Service); + if (storageOperationStatus != StorageOperationStatus.OK) { + return Either.right(componentsUtils.getResponseFormat(storageOperationStatus)); + } + + try { + for (ServiceConsumptionData serviceConsumptionData : serviceConsumptionDataList) { + Either<Operation, ResponseFormat> operationEither = + addPropertyServiceConsumption(serviceId, serviceInstanceId, operationId, + userId, serviceConsumptionData); + + if (operationEither.isRight()) { + return Either.right(operationEither.right().value()); + } + + operationList.add(operationEither.left().value()); + } + + titanDao.commit(); + return Either.left(operationList); + } catch (Exception e) { + titanDao.rollback(); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + + } finally { + graphLockOperation.unlockComponent(service.getUniqueId(), NodeTypeEnum.Service); + + } + } + + public Either <Operation, ResponseFormat> addPropertyServiceConsumption(String serviceId, + String serviceInstanceId, + String operationId, + String userId, + ServiceConsumptionData serviceConsumptionData) { + validateUserExists(userId, "create Property", false); + + Either<Service, StorageOperationStatus> serviceEither = + toscaOperationFacade.getToscaElement(serviceId); + if(serviceEither.isRight()) { + return Either.right(componentsUtils.getResponseFormat(serviceEither.right + ().value())); + } + + Service parentService = serviceEither.left().value(); + + List<ComponentInstance> componentInstances = parentService.getComponentInstances(); + if(CollectionUtils.isEmpty(componentInstances)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus + .INTERFACE_OPERATION_NOT_FOUND, serviceInstanceId)); + } + + Optional<ComponentInstance> serviceInstanceCandidate = + componentInstances.stream().filter(instance -> instance.getUniqueId().equals + (serviceInstanceId)).findAny(); + + if(!serviceInstanceCandidate.isPresent()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus + .INTERFACE_OPERATION_NOT_FOUND, serviceInstanceId)); + } + + Map<String, List<ComponentInstanceInterface>> componentInstancesInterfaces = + parentService.getComponentInstancesInterfaces(); + if(MapUtils.isEmpty(componentInstancesInterfaces)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus + .INTERFACE_OPERATION_NOT_FOUND, serviceInstanceId)); + } + + List<InterfaceDefinition> interfaces = new ArrayList<>(); + for(ComponentInstanceInterface componentInstanceInterface : + componentInstancesInterfaces.get(serviceInstanceId)) { + interfaces.add(componentInstanceInterface); + } + + ComponentInstance serviceInstance = serviceInstanceCandidate.get(); + Optional<InterfaceDefinition> interfaceCandidate = InterfaceOperationUtils + .getInterfaceDefinitionFromOperationId(interfaces, operationId); + + if(!interfaceCandidate.isPresent()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus + .INTERFACE_OPERATION_NOT_FOUND, serviceInstanceId)); + } + + InterfaceDefinition interfaceDefinition = interfaceCandidate.get(); + Map<String, Operation> operations = interfaceDefinition.getOperationsMap(); + if(MapUtils.isEmpty(operations)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus + .INTERFACE_OPERATION_NOT_FOUND, serviceInstanceId)); + } + + Operation operation = operations.get(operationId); + Either<Operation, ResponseFormat> operationEither = Either.left(operation); + + ListDataDefinition<OperationInputDefinition> inputs = operation.getInputs(); + Optional<OperationInputDefinition> inputCandidate = + getOperationInputByInputId(serviceConsumptionData, inputs); + + if(!inputCandidate.isPresent()) { + return Either.right(new ResponseFormat(HttpStatus.NOT_FOUND.value())); + } + + OperationInputDefinition operationInputDefinition = inputCandidate.get(); + + // add data to operation + + if(Objects.nonNull(serviceConsumptionData.getValue())) { + operationEither = + handleConsumptionValue(parentService, serviceInstanceId, serviceConsumptionData, operation, + operationInputDefinition); + } + + if(operationEither.isRight()) { + return Either.right(operationEither.right().value()); + } + + Operation updatedOperation = operationEither.left().value(); + operations.remove(operationId); + operations.put(operationId, updatedOperation); + interfaceDefinition.setOperationsMap(operations); + + parentService.getComponentInstances().remove(serviceInstance); + if(CollectionUtils.isEmpty(parentService.getComponentInstances())) { + parentService.setComponentInstances(new ArrayList<>()); + } + + Map<String, Object> instanceInterfaces = + MapUtils.isEmpty(serviceInstance.getInterfaces())? new HashMap<>() : serviceInstance.getInterfaces(); + instanceInterfaces.remove(interfaceDefinition.getUniqueId()); + instanceInterfaces.put(interfaceDefinition.getUniqueId(), interfaceDefinition); + serviceInstance.setInterfaces(instanceInterfaces); + + removeComponentInstanceInterfaceByInterfaceId(interfaceDefinition.getUniqueId(), componentInstancesInterfaces.get(serviceInstanceId)); + componentInstancesInterfaces.get(serviceInstanceId).add(new ComponentInstanceInterface(interfaceDefinition.getUniqueId(), interfaceDefinition)); + + parentService.getComponentInstances().add(serviceInstance); + + StorageOperationStatus status = toscaOperationFacade.updateComponentInstanceInterfaces(parentService, serviceInstanceId); + + if(status != StorageOperationStatus.OK) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus + .INTERFACE_OPERATION_NOT_FOUND, serviceInstanceId)); + } + + return Either.left(operation); + } + + private void removeComponentInstanceInterfaceByInterfaceId(String interfaceIdToRemove, + List<ComponentInstanceInterface> instanceInterfaces) { + if(CollectionUtils.isEmpty(instanceInterfaces)) { + return; + } + + Optional<ComponentInstanceInterface> interfaceToRemove = + instanceInterfaces.stream().filter(instInterface -> instInterface.getUniqueId().equals + (interfaceIdToRemove)).findAny(); + + if(interfaceToRemove.isPresent()) { + instanceInterfaces.remove(interfaceToRemove.get()); + } + + } + + private Either<Operation, ResponseFormat> handleConsumptionValue(Service containerService, + String serviceInstanceId, + ServiceConsumptionData serviceConsumptionData, + Operation operation, + OperationInputDefinition + operationInputDefinition) { + String source = serviceConsumptionData.getSource(); + String consumptionValue = serviceConsumptionData.getValue(); + String type = serviceConsumptionData.getType(); + String operationIdentifier = consumptionValue.contains(".") + ? consumptionValue.substring(0, consumptionValue.lastIndexOf('.')) + : consumptionValue; + + ServiceConsumptionSource sourceValue = ServiceConsumptionSource.getSourceValue(source); + + if(STATIC.equals(sourceValue)) { + return handleConsumptionStaticValue(consumptionValue, type, operation, + operationInputDefinition); + } + + if (Objects.isNull(sourceValue)) { + List<PropertyDefinition> propertyDefinitions; + String componentName; + List<OperationOutputDefinition> outputs = null; + if (source.equals(containerService.getUniqueId())) { + Either<Service, StorageOperationStatus> serviceToTakePropEither = + toscaOperationFacade.getToscaElement(source); + if (serviceToTakePropEither.isRight()) { + return Either.right(componentsUtils.getResponseFormat(serviceToTakePropEither.right().value())); + } + Service service = serviceToTakePropEither.left().value(); + operationInputDefinition.setSource(service.getUniqueId()); + sourceValue = SERVICE_INPUT; + propertyDefinitions = service.getProperties(); + componentName = service.getName(); + outputs = InterfaceOperationUtils.getOtherOperationOutputsOfComponent(operationIdentifier, + service.getInterfaces()).getListToscaDataDefinition(); + } else { + Optional<ComponentInstance> getComponentInstance = containerService.getComponentInstanceById(source); + if(!getComponentInstance.isPresent()){ + return Either.right(componentsUtils.getResponseFormat( + ActionStatus.COMPONENT_INSTANCE_NOT_FOUND_ON_CONTAINER, source)); + } + ComponentInstance componentInstance = getComponentInstance.get(); + operationInputDefinition.setSource(componentInstance.getUniqueId()); + propertyDefinitions = componentInstance.getProperties(); + componentName = source.equals(serviceInstanceId) ? SELF : componentInstance.getName(); + if (MapUtils.isNotEmpty(componentInstance.getInterfaces())) { + Map<String, InterfaceDataDefinition> componentInstanceInterfaces = + componentInstance.getInterfaces().entrySet().stream() + .collect(Collectors.toMap((Map.Entry::getKey), + (interfaceEntry -> (InterfaceDataDefinition) interfaceEntry.getValue()))); + outputs = InterfaceOperationUtils.getOtherOperationOutputsOfComponent(operationIdentifier, + componentInstanceInterfaces).getListToscaDataDefinition(); + } + } + + if(sourceValue == ServiceConsumptionSource.SERVICE_INPUT) { + //The operation input in service consumption has been mapped to an input in the parent service + return handleConsumptionInputValue(consumptionValue, containerService, operation, + operationInputDefinition); + } + return handleConsumptionPropertyValue(operation, operationInputDefinition, + serviceConsumptionData, propertyDefinitions, outputs, consumptionValue, componentName); + } + + operationInputDefinition.setToscaPresentationValue(JsonPresentationFields.SOURCE, source); + operationInputDefinition.setSource(source); + + return Either.left(operation); + } + + private Optional<OperationInputDefinition> getOperationInputByInputId(ServiceConsumptionData serviceConsumptionData, + ListDataDefinition<OperationInputDefinition> inputs) { + + if(CollectionUtils.isEmpty(inputs.getListToscaDataDefinition())) { + return Optional.empty(); + } + + return inputs.getListToscaDataDefinition().stream().filter(operationInput -> operationInput.getInputId().equals + (serviceConsumptionData.getInputId())) + .findAny(); + } + + private Either<Operation, ResponseFormat> handleConsumptionPropertyValue( + Operation operation, OperationInputDefinition operationInputDefinition, + ServiceConsumptionData serviceConsumptionData, List<PropertyDefinition> properties, + List<OperationOutputDefinition> outputs, String consumptionValue, String componentName) { + + if (CollectionUtils.isEmpty(properties) && CollectionUtils.isEmpty(outputs)) { + return Either.left(operation); + } + + if (CollectionUtils.isNotEmpty(outputs) + && isOperationInputMappedToOtherOperationOutput(getOperationOutputName(consumptionValue), outputs)) { + return handleConsumptionInputMappedToOperationOutput(operation, operationInputDefinition, outputs, + consumptionValue, componentName); + } + + if (CollectionUtils.isNotEmpty(properties)) { + return handleConsumptionInputMappedToProperty(operation, operationInputDefinition, serviceConsumptionData, + properties, componentName); + } + return Either.left(operation); + } + + private Either<Operation, ResponseFormat> handleConsumptionInputMappedToProperty(Operation operation, + OperationInputDefinition operationInputDefinition, ServiceConsumptionData serviceConsumptionData, + List<PropertyDefinition> properties, String componentName) { + Optional<PropertyDefinition> servicePropertyCandidate = + properties.stream().filter(property -> property.getName() + .equals(serviceConsumptionData.getValue())).findAny(); + + if (servicePropertyCandidate.isPresent()) { + boolean isInputTypeSimilarToOperation = + isAssignedValueFromValidType(operationInputDefinition.getType(), + servicePropertyCandidate.get()); + + if (!isInputTypeSimilarToOperation) { + return Either.right(componentsUtils.getResponseFormat( + ActionStatus.INVALID_CONSUMPTION_TYPE, operationInputDefinition.getType())); + } + + addPropertyToInputValue(componentName, operation, operationInputDefinition, + servicePropertyCandidate.get()); + } + return Either.left(operation); + } + + private Either<Operation, ResponseFormat> handleConsumptionInputMappedToOperationOutput(Operation operation, + OperationInputDefinition operationInputDefinition, List<OperationOutputDefinition> outputs, + String consumptionValue, String componentName) { + String outputName = getOperationOutputName(consumptionValue); + Optional<OperationOutputDefinition> servicePropertyOutputCandidate = outputs.stream() + .filter(output -> output.getName().equals(outputName)).findAny(); + if (servicePropertyOutputCandidate.isPresent()) { + boolean isInputTypeSimilarToOperation = + isAssignedValueFromValidType(operationInputDefinition.getType(), + servicePropertyOutputCandidate.get()); + if (!isInputTypeSimilarToOperation) { + return Either.right(componentsUtils.getResponseFormat( + ActionStatus.INVALID_CONSUMPTION_TYPE, operationInputDefinition.getType())); + } + addOutputToInputValue(componentName, consumptionValue, operation, operationInputDefinition); + } + return Either.left(operation); + } + + private void addPropertyToInputValue(String componentName, Operation operation, + OperationInputDefinition operationInputDefinition, + PropertyDefinition serviceProperty) { + Map<String, List<String>> getProperty = new HashMap<>(); + List<String> getPropertyValues = new ArrayList<>(); + getPropertyValues.add(componentName); + getPropertyValues.add(serviceProperty.getName()); + getProperty.put(ToscaFunctions.GET_PROPERTY.getFunctionName(), getPropertyValues); + + operationInputDefinition.setSourceProperty(serviceProperty.getUniqueId()); + operation.getInputs().delete(operationInputDefinition); + operationInputDefinition.setToscaPresentationValue(JsonPresentationFields.GET_PROPERTY, + getPropertyValues); + operationInputDefinition.setValue((new Gson()).toJson(getProperty)); + operation.getInputs().add(operationInputDefinition); + } + + private void addOutputToInputValue(String componentName, String consumptionValue, + Operation operation, OperationInputDefinition operationInputDefinition) { + Map<String, List<String>> getOperationOutput = + InterfaceOperationUtils.createMappedOutputDefaultValue(componentName, consumptionValue); + operation.getInputs().delete(operationInputDefinition); + operationInputDefinition.setToscaPresentationValue(JsonPresentationFields.GET_OPERATION_OUTPUT, + getOperationOutput); + operationInputDefinition.setValue((new Gson()).toJson(getOperationOutput)); + operation.getInputs().add(operationInputDefinition); + } + + public Either<Operation, ResponseFormat> handleConsumptionStaticValue(String value, String type, + Operation operation, + OperationInputDefinition + operationInputDefinition) { + boolean isInputTypeSimilarToOperation = + isAssignedValueFromValidType(type, value); + + if(!isInputTypeSimilarToOperation) { + return Either.right(componentsUtils.getResponseFormat( + ActionStatus.INVALID_CONSUMPTION_TYPE, type)); + } + addStaticValueToInputOperation(value, operation, operationInputDefinition); + + return Either.left(operation); + } + + private void addStaticValueToInputOperation(String value, Operation operation, + OperationInputDefinition operationInputDefinition) { + operation.getInputs().delete(operationInputDefinition); + operationInputDefinition.setSource(STATIC.getSource()); + operationInputDefinition.setSourceProperty(null); + operationInputDefinition.setValue(value); + operation.getInputs().add(operationInputDefinition); + } + + private Either<Operation, ResponseFormat> handleConsumptionInputValue(String inputId, + Service service, + Operation operation, + OperationInputDefinition + operationInputDefinition) { + List<InputDefinition> serviceInputs = service.getInputs(); + Optional<InputDefinition> inputForValue = + serviceInputs.stream().filter(input -> input.getUniqueId().contains(inputId)).findAny(); + + if(inputForValue.isPresent()) { + boolean isInputTypeSimilarToOperation = + isAssignedValueFromValidType(operationInputDefinition.getType(), inputForValue.get()); + + if(!isInputTypeSimilarToOperation) { + return Either.right(componentsUtils.getResponseFormat( + ActionStatus.INVALID_CONSUMPTION_TYPE, operationInputDefinition.getType())); + } + addGetInputValueToOperationInput(operation, operationInputDefinition, inputForValue.get()); + } + + return Either.left(operation); + } + + + private boolean isAssignedValueFromValidType(String operationInputType, Object actualValue) { + if (actualValue instanceof String) { + // validate static value + ToscaPropertyType actualType = ToscaPropertyType.isValidType(operationInputType); + PropertyTypeValidator validator = actualType.getValidator(); + return validator.isValid((String)actualValue, operationInputType); + } else if (actualValue instanceof PropertyDefinition) { + // validate input / property value + String actualType = ((PropertyDefinition) actualValue).getType(); + return actualType.equalsIgnoreCase(operationInputType); + } else if (actualValue instanceof OperationOutputDefinition) { + // validate input / output value + String actualType = ((OperationOutputDefinition) actualValue).getType(); + return actualType.equalsIgnoreCase(operationInputType); + } + return false; + } + + private void addGetInputValueToOperationInput(Operation operation, + OperationInputDefinition operationInputDefinition, + InputDefinition inputForValue) { + operation.getInputs().delete(operationInputDefinition); + Map<String, String> getInputMap = new HashMap<>(); + getInputMap.put(ToscaFunctions.GET_INPUT.getFunctionName(), inputForValue.getName()); + operationInputDefinition.setSourceProperty(inputForValue.getUniqueId()); + operationInputDefinition.setToscaPresentationValue(JsonPresentationFields.GET_INPUT, getInputMap); + operationInputDefinition.setValue(new Gson().toJson(getInputMap)); + operation.getInputs().add(operationInputDefinition); + } + private Either<List<Map<String, Object>>, ActionStatus> getAuditRecordsForUncertifiedComponent(String componentUUID, String componentVersion) { // First Query Either<List<ResourceAdminEvent>, ActionStatus> eitherprevVerAudit = auditCassandraDao.getAuditByServiceIdAndPrevVersion(componentUUID, componentVersion); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceInputsRedeclareHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceInputsRedeclareHandler.java index a60b0f0773..c09fb91d1f 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceInputsRedeclareHandler.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceInputsRedeclareHandler.java @@ -21,6 +21,7 @@ import static java.util.Collections.singletonMap; import static java.util.stream.Collectors.toList; import static org.apache.commons.collections.CollectionUtils.isEmpty; import static org.openecomp.sdc.be.dao.utils.MapUtil.toMap; +import static org.openecomp.sdc.be.utils.PropertyDefinitionUtils.resolveGetInputProperties; @org.springframework.stereotype.Component public class ComponentInstanceInputsRedeclareHandler { @@ -43,7 +44,8 @@ public class ComponentInstanceInputsRedeclareHandler { Map<String, List<PropertyDataDefinition>> allPropertiesForInstance = getAllGetPropertiesForInstance(container, newInstanceId); List<InputDefinition> previouslyDeclaredInputs = declaredInputsResolver.getPreviouslyDeclaredInputsToMerge(oldInputs, container, allPropertiesForInstance); inputsValuesMergingBusinessLogic.mergeComponentInputs(oldInputs, previouslyDeclaredInputs); - updateInputsAnnotations(allPropertiesForInstance.get(newInstanceId), newInstanceOriginType, previouslyDeclaredInputs); + Map<String, List<PropertyDataDefinition>> getInputProperties = resolveGetInputProperties(allPropertiesForInstance); + updateInputsAnnotations(getInputProperties.get(newInstanceId), newInstanceOriginType, previouslyDeclaredInputs); return updateInputs(container.getUniqueId(), previouslyDeclaredInputs); } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceInterfacesMerge.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceInterfacesMerge.java new file mode 100644 index 0000000000..60e60b0408 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceInterfacesMerge.java @@ -0,0 +1,72 @@ +package org.openecomp.sdc.be.components.merge.instance; + +import fj.data.Either; +import java.util.List; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceInterface; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.exception.ResponseFormat; +import org.springframework.beans.factory.annotation.Autowired; + +@org.springframework.stereotype.Component("ComponentInstanceInterfacesMerge") +public class ComponentInstanceInterfacesMerge implements ComponentInstanceMergeInterface { + + @Autowired + private ComponentsUtils componentsUtils; + + @Autowired + private ToscaOperationFacade toscaOperationFacade; + + @Override + public void saveDataBeforeMerge(DataForMergeHolder dataHolder, Component containerComponent, ComponentInstance currentResourceInstance, Component originComponent) { + dataHolder.setOrigInstanceNode(originComponent); + dataHolder.setOrigComponentInstanceInterfaces(containerComponent.safeGetComponentInstanceInterfaces(currentResourceInstance.getUniqueId())); + } + + @Override + public Either<Component, ResponseFormat> mergeDataAfterCreate(User user, DataForMergeHolder dataHolder, Component updatedContainerComponent, String newInstanceId) { + List<ComponentInstanceInterface> origInstanceInterfaces = dataHolder.getOrigComponentInstanceInterfaces(); + ActionStatus mergeStatus = mergeComponentInstanceInterfaces(updatedContainerComponent, newInstanceId, origInstanceInterfaces); + return Either.iif(!ActionStatus.OK.equals(mergeStatus), () -> componentsUtils.getResponseFormat(mergeStatus), () -> updatedContainerComponent); + } + + private ActionStatus mergeComponentInstanceInterfaces(Component currentComponent, String instanceId, List<ComponentInstanceInterface> prevInstanceInterfaces) { + if (CollectionUtils.isEmpty(prevInstanceInterfaces) || MapUtils.isEmpty(currentComponent.getComponentInstancesInterfaces())) { + return ActionStatus.OK; + } + + if(CollectionUtils.isEmpty(currentComponent.getComponentInstancesInterfaces().get(instanceId))){ + return ActionStatus.OK; + } + + currentComponent.getComponentInstancesInterfaces().get(instanceId).stream() + .forEach(newInterfaceDef -> newInterfaceDef.getOperationsMap().values() + .forEach(newOperationDef -> prevInstanceInterfaces.stream().filter(in -> in.getUniqueId().equals(newInterfaceDef.getUniqueId())) + .forEach(prevInterfaceDef -> prevInterfaceDef.getOperationsMap().values().stream().filter(in1 -> in1.getUniqueId().equals(newOperationDef.getUniqueId())) + .forEach(oldOperationDef -> mergeOperationInputDefinitions(oldOperationDef.getInputs(), newOperationDef.getInputs()))))); + + StorageOperationStatus updateStatus = toscaOperationFacade.updateComponentInstanceInterfaces(currentComponent, instanceId); + return componentsUtils.convertFromStorageResponse(updateStatus); + } + + + private void mergeOperationInputDefinitions(ListDataDefinition<OperationInputDefinition> origInputs, ListDataDefinition<OperationInputDefinition> newInputs){ + newInputs.getListToscaDataDefinition() + .forEach(inp -> origInputs.getListToscaDataDefinition().stream().filter(in -> in.getInputId().equals(inp.getInputId())) + .forEach(in -> { + inp.setSourceProperty(in.getSourceProperty()); + inp.setSource(in.getSource()); + inp.setValue(in.getValue()); + })); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceMergeDataBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceMergeDataBusinessLogic.java index 81e2f4ce7b..31b3207d6c 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceMergeDataBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/ComponentInstanceMergeDataBusinessLogic.java @@ -92,6 +92,7 @@ public class ComponentInstanceMergeDataBusinessLogic { filter.setIgnoreCapabiltyProperties(false); filter.setIgnoreArtifacts(false); filter.setIgnoreForwardingPath(false); + filter.setIgnoreComponentInstancesInterfaces(false); return toscaOperationFacade.getToscaElement(containerComponentId, filter); } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/DataForMergeHolder.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/DataForMergeHolder.java index 7388819ebf..b159cd510c 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/DataForMergeHolder.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/instance/DataForMergeHolder.java @@ -22,6 +22,7 @@ public class DataForMergeHolder { private Component origInstanceNode; private Component currInstanceNode; private String origComponentInstId; + private List<ComponentInstanceInterface> origComponentInstanceInterfaces; public DataForMergeHolder() { origComponentInstanceInputs = new ArrayList<>(); @@ -30,6 +31,7 @@ public class DataForMergeHolder { origCompInstDeploymentArtifactsCreatedOnTheInstance = new HashMap<>(); origCompInstDeploymentArtifactsCreatedOnTheInstance = new HashMap<>(); origInstanceCapabilities = new ArrayList<>(); + origComponentInstanceInterfaces = new ArrayList<>(); } List<ArtifactDefinition> getOrigComponentInstanceHeatEnvArtifacts() { @@ -155,4 +157,12 @@ public class DataForMergeHolder { public void setOrigComponentInstId(String origComponentInstId) { this.origComponentInstId = origComponentInstId; } + + public List<ComponentInstanceInterface> getOrigComponentInstanceInterfaces() { + return origComponentInstanceInterfaces; + } + + public void setOrigComponentInstanceInterfaces(List<ComponentInstanceInterface> origComponentInstanceInterfaces) { + this.origComponentInstanceInterfaces = origComponentInstanceInterfaces; + } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java index 06e8db0f05..bd7a58c48a 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java @@ -75,8 +75,6 @@ public abstract class DefaultPropertyDeclarator<PROPERTYOWNER extends Properties private InputDefinition declarePropertyInput(String componentId, PROPERTYOWNER propertiesOwner, List<PROPERTYTYPE> declaredProperties, ComponentInstancePropInput propInput) { PropertyDataDefinition prop = resolveProperty(declaredProperties, propInput); - propInput.setOwnerId(null); - propInput.setParentUniqueId(null); InputDefinition inputDefinition = createInput(componentId, propertiesOwner, propInput, prop); PROPERTYTYPE declaredProperty = createDeclaredProperty(prop); if(!declaredProperties.contains(declaredProperty)){ @@ -86,15 +84,19 @@ public abstract class DefaultPropertyDeclarator<PROPERTYOWNER extends Properties return inputDefinition; } - private InputDefinition createInput(String componentId, PROPERTYOWNER propertiesOwner, ComponentInstancePropInput propInput, PropertyDataDefinition prop) { - String generatedInputName = generateInputName(propertiesOwner instanceof - Service ? null : propertiesOwner.getNormalizedName(), - propInput); + private InputDefinition createInput(String componentId, PROPERTYOWNER propertiesOwner, + ComponentInstancePropInput propInput, PropertyDataDefinition prop) { + String generatedInputPrefix = propertiesOwner.getNormalizedName(); + if (propertiesOwner.getUniqueId().equals(propInput.getParentUniqueId())) { + //Creating input from property create on self using add property..Do not add the prefix + generatedInputPrefix = null; + } + String generatedInputName = generateInputName(generatedInputPrefix, propInput); return createInputFromProperty(componentId, propertiesOwner, generatedInputName, propInput, prop); } private String generateInputName(String inputName, ComponentInstancePropInput propInput) { - String declaredInputName = inputName; + String declaredInputName; String[] parsedPropNames = propInput.getParsedPropNames(); if(parsedPropNames != null){ @@ -154,7 +156,6 @@ public abstract class DefaultPropertyDeclarator<PROPERTYOWNER extends Properties input.setInputPath(propertiesName); input.setInstanceUniqueId(propertiesOwner.getUniqueId()); input.setPropertyId(propInput.getUniqueId()); - input.setValue(null); changePropertyValueToGetInputValue(inputName, parsedPropNames, input, prop, complexProperty); if(prop instanceof IComponentInstanceConnectedElement) { 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 6615e9ef37..2727a8b94a 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,17 +16,27 @@ package org.openecomp.sdc.be.components.utils; +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 java.util.Optional; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; +import org.openecomp.sdc.be.datatypes.elements.InterfaceDataDefinition; +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.datatypes.elements.OperationOutputDefinition; 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; +import org.openecomp.sdc.be.model.tosca.ToscaFunctions; +import org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil; public class InterfaceOperationUtils { @@ -66,7 +76,17 @@ public class InterfaceOperationUtils { .filter(entry -> entry.getValue().getUniqueId().equals(operationId)).findAny(); } - public static boolean isOperationInputMappedToComponentProperty(OperationInputDefinition input, + public static Optional<InterfaceDefinition> getInterfaceDefinitionFromOperationId(List<InterfaceDefinition> interfaces, + String operationId) { + if (CollectionUtils.isEmpty(interfaces)) { + return Optional.empty(); + } + return interfaces.stream() + .filter(interfaceDefinition -> interfaceDefinition.getOperationsMap().containsKey(operationId)) + .findAny(); + } + + public static boolean isOperationInputMappedToComponentInput(OperationInputDefinition input, List<InputDefinition> inputs) { if (CollectionUtils.isEmpty(inputs)) { return false; @@ -77,5 +97,87 @@ public class InterfaceOperationUtils { input.getInputId().substring(0, input.getInputId().lastIndexOf('.'))))) ; } + public static boolean isOperationInputMappedToOtherOperationOutput(String outputName, + List<OperationOutputDefinition> + otherOperationOutputs) { + if (CollectionUtils.isEmpty(otherOperationOutputs)) { + return false; + } + return otherOperationOutputs.stream() + .anyMatch(output -> output.getName().equals(outputName)); + + } + public static Map<String, List<String>> createMappedInputPropertyDefaultValue(String propertyName) { + Map<String, List<String>> getPropertyMap = new HashMap<>(); + List<String> values = new ArrayList<>(); + values.add(InterfacesOperationsToscaUtil.SELF); + if (Objects.nonNull(propertyName) && !propertyName.isEmpty()) { + values.addAll(Arrays.asList(propertyName.split("\\."))); + } + getPropertyMap.put(ToscaFunctions.GET_PROPERTY.getFunctionName(), values); + return getPropertyMap; + } + + /** + * Get the list of outputs of other operations of all the interfaces in the component. + * @param currentOperationIdentifier Fully qualified operation name e.g. org.test.interfaces.node.lifecycle.Abc.stop + * @param componentInterfaces VF or service interfaces + */ + + public static ListDataDefinition<OperationOutputDefinition> getOtherOperationOutputsOfComponent( + String currentOperationIdentifier, Map<String, ? extends InterfaceDataDefinition> componentInterfaces) { + ListDataDefinition<OperationOutputDefinition> componentOutputs = new ListDataDefinition<>(); + if (MapUtils.isEmpty(componentInterfaces)) { + return componentOutputs; + } + for (Map.Entry<String, ? extends InterfaceDataDefinition> interfaceDefinitionEntry : + componentInterfaces.entrySet()) { + String interfaceName = interfaceDefinitionEntry.getKey(); + final Map<String, OperationDataDefinition> operations = interfaceDefinitionEntry.getValue().getOperations(); + if (MapUtils.isEmpty(operations)) { + continue; + } + for (Map.Entry<String, OperationDataDefinition> operationEntry : operations.entrySet()) { + ListDataDefinition<OperationOutputDefinition> outputs = operationEntry.getValue().getOutputs(); + String expectedOperationIdentifier = interfaceName + "." + operationEntry.getKey(); + if (!currentOperationIdentifier.equals(expectedOperationIdentifier) && !outputs.isEmpty()) { + outputs.getListToscaDataDefinition().forEach(componentOutputs::add); + } + } + } + return componentOutputs; + } + + /** + * Create the value for operation input mapped to an operation output. + * @param propertyName the mapped other operation output full name + * @return input map for tosca + */ + public static Map<String, List<String>> createMappedOutputDefaultValue(String componentName, 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<>(); + String[] tokens = propertyName.split("\\."); + if (tokens.length > 2) { + defaultMappedOperationOutputValue.add(componentName); + String outputPropertyName = tokens[tokens.length - 1]; + String operationName = tokens[tokens.length - 2]; + String mappedPropertyInterfaceType = + propertyName.substring(0, propertyName.indexOf(operationName + '.' + outputPropertyName) - 1); + defaultMappedOperationOutputValue.addAll(Arrays.asList(mappedPropertyInterfaceType, operationName, + outputPropertyName)); + getOperationOutputMap.put(ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName(), + defaultMappedOperationOutputValue); + } + return getOperationOutputMap; + } + + public static String getOperationOutputName(String fullOutputIdentifier) { + return fullOutputIdentifier.contains(".") + ? fullOutputIdentifier.substring(fullOutputIdentifier.lastIndexOf('.') + 1) + : fullOutputIdentifier; + } } 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 250fc03c21..f84c9a4d86 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,10 +16,12 @@ package org.openecomp.sdc.be.components.validation; -import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.isOperationInputMappedToComponentProperty; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.getOperationOutputName; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.getOtherOperationOutputsOfComponent; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.isOperationInputMappedToComponentInput; import com.google.common.collect.Sets; -import fj.data.Either; + import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -32,10 +34,13 @@ import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; + +import fj.data.Either; 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.components.utils.InterfaceOperationUtils; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition; @@ -90,16 +95,49 @@ public class InterfaceOperationValidation { return Either.left(Boolean.TRUE); } + public Either<Boolean, ResponseFormat> validateDeleteOperationContainsNoMappedOutput( + Operation interfaceOperationToDelete, org.openecomp.sdc.be.model.Component component, + InterfaceDefinition storedInterfaceDefinition) { + ResponseFormatManager responseFormatManager = getResponseFormatManager(); + List<OperationOutputDefinition> existingOperationOutputs = + getInterfaceOperationOutputs(interfaceOperationToDelete.getUniqueId(), component.getInterfaces()); + if (existingOperationOutputs.isEmpty()) { + return Either.left(Boolean.TRUE); + } + String mappedOutputPrefix = storedInterfaceDefinition.getType() + "." + interfaceOperationToDelete.getName(); + List<OperationInputDefinition> interfaceOperationInputs = + getOtherOperationInputsOfComponent(mappedOutputPrefix, component.getInterfaces()); + Set<String> mappedOutputsInDeletedOperation = new HashSet<>(); + Set<String> existingOperationOutputNames = existingOperationOutputs.stream() + .map(OperationOutputDefinition::getName) + .collect(Collectors.toSet()); + for (String existingOperationOutputName : existingOperationOutputNames) { + Set<String> matchedOutputsMappedToInputs = interfaceOperationInputs.stream() + .filter(operationInputDefinition -> operationInputDefinition.getInputId() + .equals(mappedOutputPrefix + "." + existingOperationOutputName)) + .map(operationInputDefinition -> getOperationOutputName(operationInputDefinition.getInputId())) + .collect(Collectors.toSet()); + mappedOutputsInDeletedOperation.addAll(matchedOutputsMappedToInputs); + } + + if (CollectionUtils.isNotEmpty(mappedOutputsInDeletedOperation)) { + return getMappedOutputErrorResponse(responseFormatManager, mappedOutputsInDeletedOperation, + "Cannot delete interface operation with output(s) '{}' mapped to another operation input", + ActionStatus.INTERFACE_OPERATION_DELETE_WITH_MAPPED_OUTPUT); + } + return Either.left(Boolean.TRUE); + } + private Either<Boolean, ResponseFormat> validateAllowedOperationCountOnLocalInterfaceType( InterfaceDefinition inputInterfaceDefinition, InterfaceDefinition storedInterfaceDefinition, Map<String, InterfaceDefinition> globalInterfaceTypes, boolean isUpdate) { 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 + && isValidOperationOnLocalInterfaceType(inputInterfaceDefinition, storedInterfaceDefinition, + isUpdate)) { return Either.right(getResponseFormatManager() .getResponseFormat(ActionStatus.INTERFACE_OPERATION_INVALID_FOR_LOCAL_TYPE, inputInterfaceDefinition.getType())); @@ -108,22 +146,32 @@ public class InterfaceOperationValidation { return Either.left(Boolean.TRUE); } + private boolean isValidOperationOnLocalInterfaceType(InterfaceDefinition inputInterfaceDefinition, + InterfaceDefinition storedInterfaceDefinition, + boolean isUpdate) { + return inputInterfaceDefinition.getOperations().size() > 1 + || (!isUpdate && storedInterfaceDefinition != null + && storedInterfaceDefinition.getType() + .equalsIgnoreCase(inputInterfaceDefinition.getType())); + } + private Either<Boolean, ResponseFormat> validateAllowedOperationsOnGlobalInterfaceType( 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))); - if (!isOperationValidOnGlobalInterfaceType) { - return Either.right(getResponseFormatManager() - .getResponseFormat(ActionStatus.INTERFACE_OPERATION_INVALID_FOR_GLOBAL_TYPE, - interfaceDefinition.getType())); - } + if (globalInterfaceTypes == null) { + return Either.left(Boolean.TRUE); + } + 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())); } return Either.left(Boolean.TRUE); } @@ -212,33 +260,47 @@ public class InterfaceOperationValidation { .collect(Collectors.toSet()); } String mappedOutputPrefix = interfaceDefinition.getType() + "." + interfaceOperation.getName(); + //Get the deleted outputs (name changed also equivalent to deleted) 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()); + Set<String> deletedMappedOutputs = getModifiedMappedOutputs(deletedOutputs, mappedOutputPrefix, + component.getInterfaces()); if (CollectionUtils.isNotEmpty(deletedMappedOutputs)) { - return getMappedOutputErrorResponse(responseFormatManager, deletedMappedOutputs); + return getMappedOutputErrorResponse(responseFormatManager, deletedMappedOutputs, + "Cannot update or delete interface operation output(s) '{}' mapped to an operation input", + ActionStatus.INTERFACE_OPERATION_MAPPED_OUTPUT_MODIFIED); } if (currentOutputs != null && !currentOutputs.isEmpty()) { + //Get the unchanged outputs based on name to see if other attributes (type/mandatory) have not been changed Set<String> unchangedOutputNames = Sets.intersection(existingOperationOutputNames, currentOperationOutputNames); - Set<String> modifiedMappedOutputNames = - getModifiedMappedOutputNames(currentOutputs.getListToscaDataDefinition(), + Set<String> modifiedOutputNames = + getModifiedOutputNames(currentOutputs.getListToscaDataDefinition(), existingOperationOutputs, unchangedOutputNames); + Set<String> modifiedMappedOutputNames = getModifiedMappedOutputs(modifiedOutputNames, mappedOutputPrefix, + component.getInterfaces()); if (CollectionUtils.isNotEmpty(modifiedMappedOutputNames)) { - return getMappedOutputErrorResponse(responseFormatManager, modifiedMappedOutputNames); + return getMappedOutputErrorResponse(responseFormatManager, modifiedMappedOutputNames, + "Cannot update or delete interface operation output(s) '{}' mapped to an operation input", + ActionStatus.INTERFACE_OPERATION_MAPPED_OUTPUT_MODIFIED); } } return Either.left(Boolean.TRUE); } - private boolean isMappedOutputDeleted(String mappedOutputPrefix, String outputName, - Map<String, InterfaceDefinition> componentInterfaces) { + private Set<String> getModifiedMappedOutputs(Set<String> modifiedOutputNames, String mappedOutputPrefix, + Map<String, InterfaceDefinition> componentInterfaces) { + return modifiedOutputNames.stream() + .filter(modifiedOutputName -> isMappedOutputModified(mappedOutputPrefix, modifiedOutputName, + componentInterfaces)) + .map(InterfaceOperationUtils::getOperationOutputName) + .collect(Collectors.toSet()); + } + + private boolean isMappedOutputModified(String mappedOutputPrefix, String outputName, + Map<String, InterfaceDefinition> componentInterfaces) { List<OperationInputDefinition> interfaceOperationInputs = getOtherOperationInputsOfComponent(mappedOutputPrefix, componentInterfaces); return interfaceOperationInputs.stream() @@ -246,16 +308,16 @@ public class InterfaceOperationValidation { .equals(mappedOutputPrefix + "." + outputName)); } - private static Set<String> getModifiedMappedOutputNames(List<OperationOutputDefinition> currentOperationOutputs, - List<OperationOutputDefinition> existingOperationOutputs, - Set<String> unchangedOutputNames) { + private static Set<String> getModifiedOutputNames(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, + 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, + Map<String, OperationOutputDefinition> existingOutputMap = existingOperationOutputs.stream() + .collect(Collectors.toMap(OperationOutputDefinition::getName, (OperationOutputDefinition operationOutputDefinition) -> operationOutputDefinition)); for (String outputName : unchangedOutputNames) { @@ -270,12 +332,12 @@ public class InterfaceOperationValidation { } private Either<Boolean, ResponseFormat> getMappedOutputErrorResponse(ResponseFormatManager responseFormatManager, - Set<String> modifiedMappedOutputs) { + Set<String> modifiedMappedOutputs, + String message, + ActionStatus errorStatus) { 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_MODIFIED, modifiedOutputNameList); + LOGGER.error(message, modifiedOutputNameList); + ResponseFormat errorResponse = responseFormatManager.getResponseFormat(errorStatus, modifiedOutputNameList); return Either.right(errorResponse); } @@ -461,11 +523,11 @@ public class InterfaceOperationValidation { List<OperationInputDefinition> inputListToscaDataDefinition = operation.getInputs().getListToscaDataDefinition(); for (OperationInputDefinition inputDefinition : inputListToscaDataDefinition) { - if (isOperationInputMappedToComponentProperty(inputDefinition, component.getInputs())) { + if (isOperationInputMappedToComponentInput(inputDefinition, component.getInputs())) { isOperationInputToInputPropertyMappingValid = true; } else { mappingName = inputDefinition.getInputId().contains(".") - ? inputDefinition.getInputId().substring(inputDefinition.getInputId().lastIndexOf(".") + 1) + ? inputDefinition.getInputId().substring(inputDefinition.getInputId().lastIndexOf('.') + 1) : inputDefinition.getInputId(); break; } @@ -476,8 +538,9 @@ public class InterfaceOperationValidation { //Mapped property not found in the component properties.. Check in other operation output parameters of // component (other operation => not having the same full name) + String actualOperationIdentifier = inputInterfaceDefinition.getType() + "." + operation.getName(); ListDataDefinition<OperationOutputDefinition> outputListDataDefinition = - getOtherOperationOutputsOfComponent(inputInterfaceDefinition.getType(), operation.getName(), component); + getOtherOperationOutputsOfComponent(actualOperationIdentifier, component.getInterfaces()); List<OperationOutputDefinition> componentOutputsFromOtherOperations = outputListDataDefinition.getListToscaDataDefinition(); @@ -506,38 +569,6 @@ public class InterfaceOperationValidation { } /** - * 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 @@ -566,12 +597,6 @@ public class InterfaceOperationValidation { 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 diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/UiComponentDataConverter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/UiComponentDataConverter.java index b76664f968..0dddfe5c13 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/UiComponentDataConverter.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/UiComponentDataConverter.java @@ -20,6 +20,16 @@ package org.openecomp.sdc.be.datamodel.utils; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.toList; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.openecomp.sdc.be.components.impl.GroupTypeBusinessLogic; import org.openecomp.sdc.be.components.impl.PolicyTypeBusinessLogic; import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition; @@ -27,16 +37,21 @@ import org.openecomp.sdc.be.datatypes.components.ServiceMetadataDataDefinition; import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentFieldsEnum; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; -import org.openecomp.sdc.be.model.*; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.GroupDefinition; +import org.openecomp.sdc.be.model.PolicyDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; import org.openecomp.sdc.be.tosca.utils.NodeFilterConverter; -import org.openecomp.sdc.be.ui.model.*; +import org.openecomp.sdc.be.ui.model.UiComponentDataTransfer; +import org.openecomp.sdc.be.ui.model.UiComponentMetadata; +import org.openecomp.sdc.be.ui.model.UiResourceDataTransfer; +import org.openecomp.sdc.be.ui.model.UiResourceMetadata; +import org.openecomp.sdc.be.ui.model.UiServiceDataTransfer; +import org.openecomp.sdc.be.ui.model.UiServiceMetadata; import org.openecomp.sdc.common.log.wrappers.Logger; -import java.util.*; - -import static java.util.stream.Collectors.groupingBy; -import static java.util.stream.Collectors.toList; - @org.springframework.stereotype.Component("uiComponentDataConverter") public class UiComponentDataConverter { @@ -109,6 +124,16 @@ public class UiComponentDataConverter { NodeFilterConverter nodeFilterConverter = new NodeFilterConverter(); dataTransfer.setNodeFilterData(nodeFilterConverter.convertDataMapToUI(component.getNodeFilterComponents())); } + break; + case COMPONENT_INSTANCES_INTERFACES: + setComponentInstanceInterfaces(dataTransfer, component); + break; + case PROPERTIES: + setProperties(dataTransfer, component); + break; + case INTERFACES: + setInterfaces(dataTransfer, component); + break; default: break; } @@ -137,7 +162,6 @@ public class UiComponentDataConverter { dataTransfer.setComponentInstancesInputs(component.getComponentInstancesInputs()); } } - private void setComponentInstanceAttributes(UiComponentDataTransfer dataTransfer, Component component) { if (component.getComponentInstancesAttributes() == null) { dataTransfer.setComponentInstancesAttributes(new HashMap<>()); @@ -145,7 +169,6 @@ public class UiComponentDataConverter { dataTransfer.setComponentInstancesAttributes(component.getComponentInstancesAttributes()); } } - private void setArtifacts(UiComponentDataTransfer dataTransfer, Component component) { if (component.getArtifacts() == null) { dataTransfer.setArtifacts(new HashMap<>()); @@ -153,7 +176,6 @@ public class UiComponentDataConverter { dataTransfer.setArtifacts(component.getArtifacts()); } } - private void setToscaArtifacts(UiComponentDataTransfer dataTransfer, Component component) { if (component.getToscaArtifacts() == null) { dataTransfer.setToscaArtifacts(new HashMap<>()); @@ -221,6 +243,30 @@ public class UiComponentDataConverter { } } + private void setProperties(UiComponentDataTransfer dataTransfer, Component component) { + if (component.getProperties() == null) { + dataTransfer.setProperties(new ArrayList<>()); + } else { + dataTransfer.setProperties(component.getProperties()); + } + } + + private void setInterfaces(UiComponentDataTransfer dataTransfer, Component component) { + if (component.getInterfaces() == null) { + dataTransfer.setInterfaces(new HashMap<>()); + } else { + dataTransfer.setInterfaces(component.getInterfaces()); + } + } + + private void setComponentInstanceInterfaces(UiComponentDataTransfer dataTransfer, Component component) { + if (component.getComponentInstancesInterfaces() == null) { + dataTransfer.setComponentInstancesInterfaces(new HashMap<>()); + } else { + dataTransfer.setComponentInstancesInterfaces(component.getComponentInstancesInterfaces()); + } + } + private void setNonExcludedGroups(UiComponentDataTransfer dataTransfer, Component component) { List<GroupDefinition> groups = component.getGroups(); if (groups == null) { @@ -254,15 +300,6 @@ public class UiComponentDataConverter { continue; } switch (field) { - - case PROPERTIES: - setProperties(resource, dataTransfer); - break; - - case INTERFACES: - setInterfaces(resource, dataTransfer); - break; - case DERIVED_FROM: setDerivedFrom(resource, dataTransfer); break; @@ -287,22 +324,6 @@ public class UiComponentDataConverter { return dataTransfer; } - private void setProperties(Resource resource, UiResourceDataTransfer dataTransfer) { - if (resource.getProperties() == null) { - dataTransfer.setProperties(new ArrayList<>()); - } else { - dataTransfer.setProperties(resource.getProperties()); - } - } - - private void setInterfaces(Resource resource, UiResourceDataTransfer dataTransfer) { - if (resource.getInterfaces() == null) { - dataTransfer.setInterfaces(new HashMap<>()); - } else { - dataTransfer.setInterfaces(resource.getInterfaces()); - } - } - private void setDerivedFrom(Resource resource, UiResourceDataTransfer dataTransfer) { if (resource.getDerivedFrom() == null) { dataTransfer.setDerivedFrom(new ArrayList<>()); @@ -338,7 +359,6 @@ public class UiComponentDataConverter { switch (field) { case SERVICE_API_ARTIFACTS: setServiceApiArtifacts(service, dataTransfer); - break; case FORWARDING_PATHS: setForwardingPaths(service, dataTransfer); @@ -347,9 +367,6 @@ public class UiComponentDataConverter { UiServiceMetadata metadata = new UiServiceMetadata(service.getCategories(), (ServiceMetadataDataDefinition) service.getComponentMetadataDefinition().getMetadataDataDefinition()); dataTransfer.setMetadata(metadata); break; - case INTERFACES: - setInterfaces(service, dataTransfer); - break; default: setUiTranferDataByFieldName(dataTransfer, service, fieldName); } @@ -373,14 +390,6 @@ public class UiComponentDataConverter { } } - private void setInterfaces(Service service, UiServiceDataTransfer dataTransfer) { - if (service.getInterfaces() == null) { - dataTransfer.setInterfaces(new HashMap<>()); - } else { - dataTransfer.setInterfaces(service.getInterfaces()); - } - } - public static UiComponentMetadata convertToUiComponentMetadata(Component component) { UiComponentMetadata uiComponentMetadata = null; diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ComponentsUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ComponentsUtils.java index 0930daad04..9f6fb9fe89 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ComponentsUtils.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ComponentsUtils.java @@ -756,6 +756,9 @@ public class ComponentsUtils { case COMPONENT_IS_ARCHIVED: responseEnum = ActionStatus.COMPONENT_IS_ARCHIVED; break; + case DECLARED_INPUT_USED_BY_OPERATION: + responseEnum = ActionStatus.DECLARED_INPUT_USED_BY_OPERATION; + break; default: responseEnum = ActionStatus.GENERAL_ERROR; break; diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceConsumptionServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceConsumptionServlet.java new file mode 100644 index 0000000000..4ed2f95676 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceConsumptionServlet.java @@ -0,0 +1,245 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.be.servlets; + +import com.google.gson.Gson; +import com.google.gson.JsonParseException; +import com.jcabi.aspects.Loggable; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import fj.data.Either; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.apache.commons.lang3.StringUtils; +import org.json.simple.JSONArray; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.openecomp.sdc.be.components.impl.InterfaceOperationBusinessLogic; +import org.openecomp.sdc.be.components.impl.ServiceBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.Operation; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.tosca.ToscaFunctions; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.types.ServiceConsumptionData; +import org.openecomp.sdc.be.types.ServiceConsumptionSource; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Api(value = "Service Consumption Servlet", description = "Service Consumption Servlet") +@Singleton +public class ServiceConsumptionServlet extends BeGenericServlet { + + private static final Logger log = LoggerFactory.getLogger(ServiceConsumptionServlet.class); + + @POST + @Path("/services/{serviceId}/consumption/{serviceInstanceId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Service consumption on operation", httpMethod = "POST", + notes = "Returns consumption data", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Service property created"), + @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Service property already exist") }) + public Response addInputToServiceOperation(@PathParam("serviceId")final String serviceId, + @PathParam("serviceInstanceId")final String serviceInstanceId, + @ApiParam(value = "Service Consumption Data", required = true) String data, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {} modifier id is {} data is {}", url, userId, data); + User modifier = new User(); + modifier.setUserId(userId); + + try { + + Either<Map<String, List<ServiceConsumptionData>>, ResponseFormat> dataFromJson = + getServiceConsumptionData(data, modifier); + if(dataFromJson.isRight()) { + return buildErrorResponse(dataFromJson.right().value()); + } + + Map<String, List<ServiceConsumptionData>> serviceConsumptionDataMap = dataFromJson.left().value(); + ServiceBusinessLogic serviceBL = getServiceBL(context); + + for(Entry<String, List<ServiceConsumptionData>> consumptionEntry : serviceConsumptionDataMap.entrySet()) { + List<ServiceConsumptionData> consumptionList = consumptionEntry.getValue(); + Either<List<Operation>, ResponseFormat> operationEither = + serviceBL.addServiceConsumptionData(serviceId, serviceInstanceId, + consumptionEntry.getKey(), consumptionList, userId); + if (operationEither.isRight()) { + return buildErrorResponse(operationEither.right().value()); + } + } + + return buildOkResponse(serviceConsumptionDataMap); + + } + catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Operation Inputs"); + log.debug("Create Operation Inputs failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + } + + } + + @GET + @Path("/services/{serviceId}/consumption/{serviceInstanceId}/interfaces/{interfaceId}/operations/{operationId}/inputs") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response getInputsListOfOperation(@PathParam("serviceId")final String serviceId, + @PathParam("serviceInstanceId")final String serviceInstanceId, + @PathParam("interfaceId")final String interfaceId, + @PathParam("operationId")final String operationId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {} modifier id is {}", url, userId); + User user = new User(); + user.setUserId(userId); + + try { + InterfaceOperationBusinessLogic interfaceOperationBL = getInterfaceOperationBL(context); + Either<List<OperationInputDefinition>, ResponseFormat> inputsEither = + interfaceOperationBL.getInputsListForOperation(serviceId, serviceInstanceId, interfaceId, operationId, user); + + if(inputsEither.isRight()) { + return buildErrorResponse(inputsEither.right().value()); + } + + List<OperationInputDefinition> inputs = inputsEither.left().value(); + updateOperationInputListForUi(inputs); + return buildOkResponse(inputs); + } + catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Operation Inputs"); + log.debug("Get Operation Inputs failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + } + } + + private void updateOperationInputListForUi(List<OperationInputDefinition> inputsList) { + for(OperationInputDefinition input : inputsList) { + + String value = input.getValue(); + // No Additional UI mapping needed for STATIC source + if(StringUtils.isEmpty(value) + || ServiceConsumptionSource.STATIC.getSource().equals(input.getSource())) { + continue; + } + + + // Additional UI mapping needed for other sources + try { + Map<String, Object> valueAsMap = (new Gson()).fromJson(value, Map.class); + String toscaFunction = valueAsMap.keySet().iterator().next(); + Object consumptionValueName = valueAsMap.values().iterator().next(); + if(consumptionValueName instanceof List) { + List<Object> toscaFunctionList = (List<Object>) consumptionValueName; + String consumptionInputValue = null; + if (ToscaFunctions.GET_PROPERTY.getFunctionName().equals(toscaFunction)) { + consumptionInputValue = String.valueOf(toscaFunctionList.get(1)); + } else if (ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName().equals(toscaFunction)) { + //Return full output name + consumptionInputValue = + toscaFunctionList.get(1) + "." + toscaFunctionList.get(2) + "." +toscaFunctionList.get(3); + } + input.setValue(consumptionInputValue); + } else { + input.setValue(String.valueOf(consumptionValueName)); + } + } + catch(JsonParseException ex){ + log.info("This means it is static value for which no changes are needed"); + } + } + } + + + private Either<Map<String, List<ServiceConsumptionData>>, ResponseFormat> getServiceConsumptionData(String data, + User user) { + JSONParser parser = new JSONParser(); + Map<String, List<ServiceConsumptionData>> serviceConsumptionDataMap = new HashMap<>(); + + try { + JSONArray operationsArray = (JSONArray) parser.parse(data); + Iterator iterator = operationsArray.iterator(); + while (iterator.hasNext()) { + Map next = (Map) iterator.next(); + Entry consumptionEntry = (Entry) next.entrySet().iterator().next(); + String operationId = (String) consumptionEntry.getKey(); + Object value = consumptionEntry.getValue(); + + JSONArray inputsArray = (JSONArray) parser.parse(value.toString()); + serviceConsumptionDataMap.putIfAbsent(operationId, new ArrayList<>()); + for(Object consumptionObject : inputsArray) { + Either<ServiceConsumptionData, ResponseFormat> serviceDataEither = + getComponentsUtils() + .convertJsonToObjectUsingObjectMapper(consumptionObject.toString(), user, ServiceConsumptionData + .class, AuditingActionEnum.CREATE_RESOURCE, ComponentTypeEnum.SERVICE); + if(serviceDataEither.isRight()) { + return Either.right(serviceDataEither.right().value()); + } + + serviceConsumptionDataMap.get(operationId).add(serviceDataEither.left().value()); + } + } + } + catch (ParseException e) { + log.info("Conetnt is invalid - {}", data); + return Either.right(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + return Either.left(serviceConsumptionDataMap); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java index da0ec1c0ea..d3d4c2d073 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java @@ -45,6 +45,7 @@ import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; import org.openecomp.sdc.be.model.jsontitan.utils.ModelConverter; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation; +import org.openecomp.sdc.be.model.tosca.ToscaFunctions; import org.openecomp.sdc.be.model.tosca.converters.ToscaValueBaseConverter; import org.openecomp.sdc.be.tosca.model.*; import org.openecomp.sdc.be.tosca.utils.ForwardingPathToscaUtil; @@ -509,27 +510,8 @@ public class ToscaExportHandler { } private Either<ToscaTemplate, ToscaError> convertNodeType(Map<String, Component> componentsCache, Component component, ToscaTemplate toscaNode, - Map<String, ToscaNodeType> nodeTypes) { - log.debug("start convert node type for {}", component.getUniqueId()); - ToscaNodeType toscaNodeType = createNodeType(component); - - Either<Map<String, DataTypeDefinition>, TitanOperationStatus> dataTypesEither = dataTypeCache.getAll(); - if (dataTypesEither.isRight()) { - log.debug("Failed to fetch all data types :", dataTypesEither.right().value()); - return Either.right(ToscaError.GENERAL_ERROR); - } - - Map<String, DataTypeDefinition> dataTypes = dataTypesEither.left().value(); - Either<ToscaNodeType, ToscaError> properties = propertyConvertor.convertProperties(component, toscaNodeType, - dataTypes); - if (properties.isRight()) { - return Either.right(properties.right().value()); - } - toscaNodeType = properties.left().value(); - log.debug("Properties converted for {}", component.getUniqueId()); - - // Extracted to method for code reuse - return convertReqCapAndTypeName(componentsCache, component, toscaNode, nodeTypes, toscaNodeType, dataTypes); + Map<String, ToscaNodeType> nodeTypes) { + return convertInterfaceNodeType(componentsCache, component, toscaNode, nodeTypes, false); } private Either<ToscaTemplate, ToscaError> convertInterfaceNodeType(Map<String, Component> componentsCache, @@ -546,10 +528,10 @@ public class ToscaExportHandler { return Either.right(ToscaError.GENERAL_ERROR); } List<String> allGlobalInterfaceTypes = lifecycleTypeEither.left().value() - .values() - .stream() - .map(interfaceDef -> interfaceDef.getType()) - .collect(Collectors.toList()); + .values() + .stream() + .map(InterfaceDataDefinition::getType) + .collect(Collectors.toList()); toscaNode.setInterface_types(addInterfaceTypeElement(component, allGlobalInterfaceTypes)); Either<Map<String, DataTypeDefinition>, TitanOperationStatus> dataTypesEither = dataTypeCache.getAll(); @@ -570,16 +552,40 @@ public class ToscaExportHandler { if(CollectionUtils.isNotEmpty(component.getProperties())) { List<PropertyDefinition> properties = component.getProperties(); mergedProperties = properties.stream().collect(Collectors.toMap( - PropertyDataDefinition::getName, - property -> propertyConvertor.convertProperty(dataTypes, property, PropertyConvertor.PropertyType.PROPERTY))); + PropertyDataDefinition::getName, + property -> propertyConvertor.convertProperty(dataTypes, property, + PropertyConvertor.PropertyType.PROPERTY))); } - if (!mergedProperties.isEmpty()) { + if (MapUtils.isNotEmpty(mergedProperties) && Objects.nonNull(inputDef)) { + resolveDefaultPropertyValue(inputDef, mergedProperties, dataTypes); toscaNodeType.setProperties(mergedProperties); } // Extracted to method for code reuse return convertReqCapAndTypeName(componentsCache, component, toscaNode, nodeTypes, toscaNodeType, dataTypes); } + private void resolveDefaultPropertyValue(List<InputDefinition> inputDef, + Map<String, ToscaProperty> mergedProperties, + Map<String, DataTypeDefinition> dataTypes) { + for (Map.Entry<String, ToscaProperty> mergedPropertyEntry : mergedProperties.entrySet()) { + ToscaProperty value = mergedPropertyEntry.getValue(); + if (Objects.nonNull(value) && value.getDefaultp() instanceof Map) { + Map<String, String> valueAsMap = (Map<String, String>) value.getDefaultp(); + String inputName = valueAsMap.get(ToscaFunctions.GET_INPUT.getFunctionName()); + Optional<InputDefinition> matchedInputDefinition = inputDef.stream() + .filter(componentInput -> componentInput.getName().equals(inputName)) + .findFirst(); + if (matchedInputDefinition.isPresent()) { + InputDefinition matchedInput = matchedInputDefinition.get(); + Object resolvedDefaultValue = new PropertyConvertor().convertToToscaObject(matchedInput.getType(), + matchedInput.getDefaultValue(), matchedInput.getSchemaType(), dataTypes, false); + value.setDefaultp(resolvedDefaultValue); + mergedProperties.put(mergedPropertyEntry.getKey(), value); + } + } + } + } + private void addInputsToProperties(Map<String, DataTypeDefinition> dataTypes, List<InputDefinition> inputDef, Map<String, ToscaProperty> mergedProperties) { @@ -692,12 +698,14 @@ public class ToscaExportHandler { addPropertiesOfParentComponent(dataTypes, originalComponent, props); } - if (null != componentInstancesProperties && componentInstancesProperties.containsKey(instanceUniqueId)) { + if (null != componentInstancesProperties && componentInstancesProperties.containsKey(instanceUniqueId) + && !isComponentOfTypeServiceProxy(componentInstance)) { addPropertiesOfComponentInstance(componentInstancesProperties, dataTypes, instanceUniqueId, props); } - if (componentInstancesInputs != null && componentInstancesInputs.containsKey(instanceUniqueId)) { + if (componentInstancesInputs != null && componentInstancesInputs.containsKey(instanceUniqueId) + && !isComponentOfTypeServiceProxy(componentInstance)) { addComponentInstanceInputs(dataTypes, componentInstancesInputs, instanceUniqueId, props); } @@ -821,8 +829,8 @@ public class ToscaExportHandler { if (instanceInputsList != null) { instanceInputsList.forEach(input -> { - Supplier<String> supplier = () -> input.getValue() != null && !input.getValue().isEmpty() - ? input.getValue() : input.getDefaultValue(); + Supplier<String> supplier = () -> input.getValue() != null && !Objects.isNull(input.getValue()) + ? input.getValue() : input.getDefaultValue(); propertyConvertor.convertAndAddValue(dataTypes, props, input, supplier); }); } @@ -844,13 +852,13 @@ public class ToscaExportHandler { private void addPropertiesOfParentComponent(Map<String, DataTypeDefinition> dataTypes, Component componentOfInstance, Map<String, Object> props) { - List<PropertyDefinition> componentProperties = ((Resource) componentOfInstance).getProperties(); + List<PropertyDefinition> componentProperties = componentOfInstance.getProperties(); if (isNotEmpty(componentProperties)) { componentProperties.stream() - // Filters out properties with empty default values - .filter(prop -> isNotEmpty(prop.getDefaultValue())) - // Converts and adds each value to property map - .forEach(prop -> propertyConvertor.convertAndAddValue(dataTypes, props, prop, + // Filters out properties with empty default values + .filter(prop -> StringUtils.isNotEmpty(prop.getDefaultValue())) + // Converts and adds each value to property map + .forEach(prop -> propertyConvertor.convertAndAddValue(dataTypes, props, prop, prop::getDefaultValue)); } } 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 a72f57d61c..d69e4f67b3 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,16 +16,15 @@ 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; -import java.util.ArrayList; -import java.util.Arrays; +import com.google.gson.Gson; + 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; @@ -33,6 +32,8 @@ import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.model.InterfaceDefinition; import org.openecomp.sdc.be.model.Product; +import org.openecomp.sdc.be.model.tosca.ToscaFunctions; +import org.openecomp.sdc.be.tosca.PropertyConvertor; import org.openecomp.sdc.be.tosca.model.ToscaInterfaceDefinition; import org.openecomp.sdc.be.tosca.model.ToscaInterfaceNodeType; import org.openecomp.sdc.be.tosca.model.ToscaLifecycleOperationDefinition; @@ -50,9 +51,7 @@ public class InterfacesOperationsToscaUtil { private static final String DOT = "."; 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"; + public static final String SELF = "SELF"; private InterfacesOperationsToscaUtil() { } @@ -153,7 +152,7 @@ public class InterfacesOperationsToscaUtil { toscaOperation.setImplementation(operationArtifactPath); } toscaOperation.setDescription(operationEntry.getValue().getDescription()); - fillToscaOperationInputs(operationEntry.getValue(), toscaOperation, component); + fillToscaOperationInputs(operationEntry.getValue(), dataTypes, toscaOperation, isServiceProxyInterface); toscaOperations.put(operationEntry.getValue().getName(), toscaOperation); } @@ -162,6 +161,7 @@ public class InterfacesOperationsToscaUtil { Map<String, Object> interfaceDefAsMap = getObjectAsMap(toscaInterfaceDefinition); Map<String, Object> operationsMap = (Map<String, Object>) interfaceDefAsMap.remove(OPERATIONS_KEY); if (isServiceProxyInterface) { + //Remove input type and copy default value directly into the proxy node template from the node type handleServiceProxyOperationInputValue(operationsMap, interfaceType); } else { handleDefaults(operationsMap); @@ -235,8 +235,9 @@ public class InterfacesOperationsToscaUtil { } private static void fillToscaOperationInputs(OperationDataDefinition operation, + Map<String, DataTypeDefinition> dataTypes, ToscaLifecycleOperationDefinition toscaOperation, - Component component) { + boolean isServiceProxyInterface) { if (Objects.isNull(operation.getInputs()) || operation.getInputs().isEmpty()) { toscaOperation.setInputs(null); return; @@ -246,61 +247,37 @@ public class InterfacesOperationsToscaUtil { for (OperationInputDefinition input : operation.getInputs().getListToscaDataDefinition()) { ToscaProperty toscaInput = new ToscaProperty(); toscaInput.setDescription(input.getDescription()); - String mappedPropertyName; - if (Objects.nonNull(input.getInputId())) { - 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)); - } - } toscaInput.setType(input.getType()); toscaInput.setRequired(input.isRequired()); + if (isServiceProxyInterface) { + String inputValue = Objects.nonNull(input.getValue()) ? getInputValue(input.getValue()) : + getInputValue(input.getToscaDefaultValue()); + toscaInput.setDefaultp(new PropertyConvertor().convertToToscaObject(input.getType(), + inputValue, input.getSchemaType(), dataTypes, false)); + } else { + toscaInput.setDefaultp(new PropertyConvertor().convertToToscaObject(input.getType(), + getInputValue(input.getToscaDefaultValue()), input.getSchemaType(), dataTypes, false)); + } toscaInputs.put(input.getName(), toscaInput); } - toscaOperation.setInputs(toscaInputs); } - private static Map<String, List<String>> createMappedInputPropertyDefaultValue(String propertyName) { - Map<String, List<String>> getPropertyMap = new HashMap<>(); - List<String> values = new ArrayList<>(); - values.add(SELF); - if (Objects.nonNull(propertyName) && !propertyName.isEmpty()) { - values.addAll(Arrays.asList(propertyName.split("\\."))); - } - - getPropertyMap.put(GET_PROPERTY, values); - - return getPropertyMap; - } - - /** - * Create the value for operation input mapped to an operation output. - * @param propertyName the mapped other operation output full name - * @return input map for tosca - */ - 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<>(); - 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); + private static String getInputValue(String inputValue) { + String toscaInputValue = inputValue; + if (Objects.nonNull(inputValue) && inputValue.contains(ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName())) { + Gson gson = new Gson(); + Map<String, List<String>> consumptionValue = gson.fromJson(inputValue, Map.class); + List<String> mappedOutputValue = + consumptionValue.get(ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName()); + //Extract the interface name from the interface type + String interfaceType = mappedOutputValue.get(1); + String interfaceName = interfaceType.substring(interfaceType.lastIndexOf('.') + 1); + mappedOutputValue.remove(1); + mappedOutputValue.add(1, interfaceName); + toscaInputValue = gson.toJson(consumptionValue); } - return getOperationOutputMap; + return toscaInputValue; } private static Map<String, Object> getObjectAsMap(Object obj) { diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/types/ServiceConsumptionData.java b/catalog-be/src/main/java/org/openecomp/sdc/be/types/ServiceConsumptionData.java new file mode 100644 index 0000000000..5e97ac67f4 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/types/ServiceConsumptionData.java @@ -0,0 +1,56 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.be.types; + +public class ServiceConsumptionData { + private String inputId; + private String source; + private String value; + private String type; + + public String getInputId() { + return inputId; + } + + public void setInputId(String inputId) { + this.inputId = inputId; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/types/ServiceConsumptionSource.java b/catalog-be/src/main/java/org/openecomp/sdc/be/types/ServiceConsumptionSource.java new file mode 100644 index 0000000000..9e297b7c45 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/types/ServiceConsumptionSource.java @@ -0,0 +1,49 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.be.types; + +import java.util.HashMap; +import java.util.Map; + +public enum ServiceConsumptionSource { + SERVICE_INPUT("ServiceInput"), + STATIC("Static"); + + + private static Map<String, ServiceConsumptionSource> sourceToValue; + + static { + sourceToValue = new HashMap<>(); + for(ServiceConsumptionSource sourceName : ServiceConsumptionSource.values()) { + sourceToValue.put(sourceName.source, sourceName); + } + } + + private String source; + + ServiceConsumptionSource(String source) { + this.source = source; + } + + public static ServiceConsumptionSource getSourceValue(String source) { + return sourceToValue.get(source); + } + + public String getSource() { + return source; + } +} diff --git a/catalog-be/src/main/resources/config/error-configuration.yaml b/catalog-be/src/main/resources/config/error-configuration.yaml index 0908afc628..d9f8ffc7e4 100644 --- a/catalog-be/src/main/resources/config/error-configuration.yaml +++ b/catalog-be/src/main/resources/config/error-configuration.yaml @@ -2250,10 +2250,16 @@ errors: message: "Error: Cannot update or delete interface operation output(s) '%1' mapped to an operation input", messageId: "SVC4723" } -#---------SVC4723----------------------------- +#---------SVC4724----------------------------- # %1 - Interface Operation output name - INTERFACE_OPERATION_MAPPED_OUTPUT_MODIFIED: { + INTERFACE_OPERATION_DELETE_WITH_MAPPED_OUTPUT: { code: 400, - message: "Error: Cannot update or delete interface operation output(s) '%1' mapped to an operation input", - messageId: "SVC4723" + message: "Error: Cannot delete interface operation with output(s) '%1' mapped to another operation input", + messageId: "SVC4724" + } +#---------SVC4725----------------------------- + INVALID_CONSUMPTION_TYPE: { + code: 400, + message: "Error: Given value is different than input type. Needs to be %1", + messageId: "SVC4725" }
\ No newline at end of file |