diff options
author | aribeiro <anderson.ribeiro@est.tech> | 2020-11-19 13:28:43 +0000 |
---|---|---|
committer | Christophe Closset <christophe.closset@intl.att.com> | 2021-01-29 08:22:04 +0000 |
commit | 5c1f5756bcb5856e2d8b35e3c6ac206f891f8695 (patch) | |
tree | 29a7c4424b3ced8800e5bcacc629c8fff8dd8753 /catalog-be/src/main/java | |
parent | 3c957597725f306b4ca06cebfa54fbf0f2622938 (diff) |
Add support for updating interface operations
Allows to update interface operations on a component instance.
Issue-ID: SDC-3446
Signed-off-by: aribeiro <anderson.ribeiro@est.tech>
Signed-off-by: andre.schmid <andre.schmid@est.tech>
Change-Id: I6a2c44997c04d9d9ea298e3d0bc971da7b137799
Diffstat (limited to 'catalog-be/src/main/java')
7 files changed, 561 insertions, 108 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 7c463ac387..1104621379 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 @@ -349,17 +349,17 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { final OriginTypeEnum originType = resourceInstance.getOriginType(); validateInstanceName(resourceInstance); if (originType == OriginTypeEnum.ServiceProxy) { - origComponent = getOrigComponentForServiceProxy(containerComponent, resourceInstance); - } else if (originType == OriginTypeEnum.ServiceSubstitution){ - origComponent = getOrigComponentForServiceSubstitution(resourceInstance); - } else { - origComponent = getAndValidateOriginComponentOfComponentInstance(containerComponent, resourceInstance); - validateOriginAndResourceInstanceTypes(containerComponent, origComponent, originType); - } - validateResourceInstanceState(containerComponent, origComponent); - overrideFields(origComponent, resourceInstance); - compositionBusinessLogic.validateAndSetDefaultCoordinates(resourceInstance); + origComponent = getOrigComponentForServiceProxy(containerComponent, resourceInstance); + } else if (originType == OriginTypeEnum.ServiceSubstitution) { + origComponent = getOrigComponentForServiceSubstitution(resourceInstance); + } else { + origComponent = getAndValidateOriginComponentOfComponentInstance(containerComponent, resourceInstance); + validateOriginAndResourceInstanceTypes(containerComponent, origComponent, originType); } + validateResourceInstanceState(containerComponent, origComponent); + overrideFields(origComponent, resourceInstance); + compositionBusinessLogic.validateAndSetDefaultCoordinates(resourceInstance); + } return createComponent(needLock, containerComponent,origComponent, resourceInstance, user); } @@ -2444,6 +2444,10 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { ActionStatus actionStatus = ActionStatus.COMPONENT_IS_ARCHIVED; throw new ByActionStatusComponentException(actionStatus, component.getName()); } + final Map<String, InterfaceDefinition> componentInterfaces = component.getInterfaces(); + if(MapUtils.isNotEmpty(componentInterfaces)) { + componentInterfaces.forEach(componentInstance::addInterface); + } return component; } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java new file mode 100644 index 0000000000..e32c51f7da --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java @@ -0,0 +1,221 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2021 Nordix Foundation. All rights reserved. + * ================================================================================ + * 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.zone-instance.component.ts + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import fj.data.Either; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.openecomp.sdc.be.components.impl.exceptions.BusinessLogicException; +import org.openecomp.sdc.be.components.validation.ComponentValidations; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +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.ComponentParametersView; +import org.openecomp.sdc.be.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations; +import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation; +import org.openecomp.sdc.be.model.operations.api.IElementOperation; +import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation; +import org.openecomp.sdc.be.model.operations.api.IGroupOperation; +import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +@org.springframework.stereotype.Component("componentInterfaceOperationBusinessLogic") +public class ComponentInterfaceOperationBusinessLogic extends BaseBusinessLogic { + + private final ComponentValidations componentValidations; + + private static final Logger LOGGER = LoggerFactory.getLogger(ComponentInterfaceOperationBusinessLogic .class); + + @Autowired + public ComponentInterfaceOperationBusinessLogic(final IElementOperation elementDao, + final IGroupOperation groupOperation, + final IGroupInstanceOperation groupInstanceOperation, + final IGroupTypeOperation groupTypeOperation, + final InterfaceOperation interfaceOperation, + final InterfaceLifecycleOperation interfaceLifecycleTypeOperation, + final ArtifactsOperations artifactToscaOperation, + final ComponentValidations componentValidations) { + super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, + interfaceLifecycleTypeOperation, artifactToscaOperation); + this.componentValidations = componentValidations; + } + + public Optional<ComponentInstance> updateComponentInstanceInterfaceOperation(final String componentId, + final String componentInstanceId, + final InterfaceDefinition interfaceDefinition, + final ComponentTypeEnum componentTypeEnum, + final Wrapper<ResponseFormat> errorWrapper, + final boolean shouldLock) + throws BusinessLogicException { + + final Component component = getComponent(componentId); + final Optional<ComponentInstance> componentInstanceOptional = componentValidations + .getComponentInstance(component, componentInstanceId); + ResponseFormat responseFormat; + if (componentInstanceOptional.isEmpty()) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND); + LOGGER.debug("Failed to found component instance with id {}, error: {}", + componentInstanceId, responseFormat); + errorWrapper.setInnerElement(responseFormat); + return Optional.empty(); + } + + Map<String, List<ComponentInstanceInterface>> componentInstancesInterfaceMap = component + .getComponentInstancesInterfaces(); + if (MapUtils.isEmpty(componentInstancesInterfaceMap)) { + componentInstancesInterfaceMap = new HashMap<>(); + component.setComponentInstancesInterfaces(componentInstancesInterfaceMap); + } + final List<ComponentInstanceInterface> componentInstanceInterfaceList = componentInstancesInterfaceMap + .get(componentInstanceId); + + if (CollectionUtils.isEmpty(componentInstanceInterfaceList)) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND); + LOGGER.debug("Failed to found component instance with id {}, error: {}", + componentInstanceId, responseFormat); + errorWrapper.setInnerElement(responseFormat); + return Optional.empty(); + } + + final Optional<OperationDataDefinition> optionalOperationDataDefinition = interfaceDefinition + .getOperations().values().stream().findFirst(); + if (optionalOperationDataDefinition.isEmpty()) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND); + LOGGER.debug("Failed to found interface operation on component instance with id {}, error: {}", + componentInstanceId, responseFormat); + errorWrapper.setInnerElement(responseFormat); + return Optional.empty(); + } + final OperationDataDefinition updatedOperationDataDefinition = optionalOperationDataDefinition.get(); + final Optional<ComponentInstanceInterface> optionalComponentInstanceInterface = componentInstanceInterfaceList + .stream().filter(ci -> ci.getOperations().values().stream().anyMatch(operationDataDefinition -> + operationDataDefinition.getUniqueId() + .equalsIgnoreCase(updatedOperationDataDefinition.getUniqueId()))).findFirst(); + + if (optionalComponentInstanceInterface.isEmpty()) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.INTERFACE_NOT_FOUND_IN_COMPONENT); + LOGGER.debug("Failed to found ComponentInstanceInterface on component instance with id {}, error: {}", + componentInstanceId, responseFormat); + errorWrapper.setInnerElement(responseFormat); + return Optional.empty(); + } + + updateOperationDefinitionImplementation(updatedOperationDataDefinition); + + optionalComponentInstanceInterface.get().getOperations() + .replace(updatedOperationDataDefinition.getName(), updatedOperationDataDefinition); + + boolean wasLocked = false; + try { + if (shouldLock) { + lockComponent(componentId, component, "Update Interface Operation on Component instance"); + wasLocked = true; + } + + final StorageOperationStatus status = toscaOperationFacade + .updateComponentInstanceInterfaces(component, componentInstanceId); + + if (status != StorageOperationStatus.OK) { + janusGraphDao.rollback(); + responseFormat = componentsUtils + .getResponseFormat(ActionStatus.GENERAL_ERROR); + LOGGER.error("Exception occurred when updating Component Instance Interfaces {}", responseFormat); + errorWrapper.setInnerElement(responseFormat); + return Optional.empty(); + } + + final ComponentParametersView componentFilter = new ComponentParametersView(); + componentFilter.disableAll(); + componentFilter.setIgnoreUsers(false); + componentFilter.setIgnoreComponentInstances(false); + componentFilter.setIgnoreInterfaces(false); + componentFilter.setIgnoreComponentInstancesInterfaces(false); + + final Either<Component, StorageOperationStatus> operationStatusEither = toscaOperationFacade + .updateComponentInstanceMetadataOfTopologyTemplate(component, componentFilter); + + if (operationStatusEither.isRight()) { + janusGraphDao.rollback(); + responseFormat = componentsUtils + .getResponseFormat(ActionStatus.GENERAL_ERROR); + LOGGER.error("Exception occurred when updating Component Instance Topology template {}", responseFormat); + errorWrapper.setInnerElement(responseFormat); + return Optional.empty(); + } + janusGraphDao.commit(); + + } catch (final Exception e) { + janusGraphDao.rollback(); + LOGGER.error("Exception occurred when updating Interface Operation on Component Instance: {}", + e.getMessage(), e); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + errorWrapper.setInnerElement(responseFormat); + throw new BusinessLogicException(responseFormat); + + } finally { + if (wasLocked) { + unlockComponent(component.getUniqueId(), componentTypeEnum); + } + } + + return componentInstanceOptional; + + } + + public User validateUser(final String userId) { + final User user = userValidations.validateUserExists(userId); + userValidations + .validateUserRole(user, Arrays.asList(Role.DESIGNER, Role.ADMIN)); + return user; + } + + private void unlockComponent(final String componentUniqueId, + final ComponentTypeEnum componentType) { + graphLockOperation.unlockComponent(componentUniqueId, componentType.getNodeType()); + } + + private void updateOperationDefinitionImplementation(final OperationDataDefinition updatedOperationDataDefinition) { + final ArtifactDataDefinition artifactInfo = new ArtifactDataDefinition(); + artifactInfo.setArtifactName( + String.format("'%s'", updatedOperationDataDefinition.getImplementation().getArtifactName()) + ); + updatedOperationDataDefinition.setImplementation(artifactInfo); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceDefinitionHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceDefinitionHandler.java index aeb4376c15..71005ef0f0 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceDefinitionHandler.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceDefinitionHandler.java @@ -38,6 +38,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; +import java.util.UUID; import java.util.stream.Collectors; import org.apache.commons.collections.MapUtils; import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum; @@ -172,9 +173,13 @@ public class InterfaceDefinitionHandler { private OperationDataDefinition createOperation(final String operationName, final Map<String, Object> operationDefinitionMap) { final OperationDataDefinition operation = new OperationDataDefinition(); + operation.setUniqueId(UUID.randomUUID().toString()); operation.setName(operationName); - handleOperationImplementation(operationDefinitionMap).ifPresent(operation::setImplementation); + operation.setImplementation( + handleOperationImplementation(operationDefinitionMap) + .orElse(new ArtifactDataDefinition()) + ); if (operationDefinitionMap.containsKey(INPUTS.getElementName())) { final Map<String, Object> interfaceInputs = (Map<String, Object>) operationDefinitionMap.get(INPUTS.getElementName()); @@ -189,6 +194,8 @@ public class InterfaceDefinitionHandler { final ListDataDefinition<OperationInputDefinition> inputs = new ListDataDefinition<>(); for (final Entry<String, Object> interfaceInput : interfaceInputs.entrySet()) { final OperationInputDefinition operationInput = new OperationInputDefinition(); + operationInput.setUniqueId(UUID.randomUUID().toString()); + operationInput.setInputId(operationInput.getUniqueId()); operationInput.setName(interfaceInput.getKey()); if (interfaceInput.getValue() instanceof Map) { final LinkedHashMap<String, Object> inputPropertyValue = diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java index b96e4e58e2..6137a3ffca 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java @@ -375,7 +375,8 @@ public class ResourceImportManager { log.info("error when creating interface:{}, for resource:{}", interfaceNameValue.getKey(), resource.getName()); } else { - moduleInterfaces.put(interfaceNameValue.getKey(), eitherInterface.left().value()); + final InterfaceDefinition interfaceDefinition = eitherInterface.left().value(); + moduleInterfaces.put(interfaceNameValue.getKey(), interfaceDefinition); } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInterfaceOperationServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInterfaceOperationServlet.java new file mode 100644 index 0000000000..c2e668c049 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInterfaceOperationServlet.java @@ -0,0 +1,179 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2021 Nordix Foundation. All rights reserved. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import fj.data.Either; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import java.io.IOException; +import java.util.Optional; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +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; +import org.apache.commons.io.IOUtils; +import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic; +import org.openecomp.sdc.be.components.impl.ComponentInterfaceOperationBusinessLogic; +import org.openecomp.sdc.be.components.impl.ResourceImportManager; +import org.openecomp.sdc.be.components.impl.aaf.AafPermission; +import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.impl.ServletUtils; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.ui.model.UiComponentDataTransfer; +import org.openecomp.sdc.be.user.UserBusinessLogic; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; + +@Path("/v1/catalog/{componentType}/{componentId}/componentInstance/{componentInstanceId}/interfaceOperation") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Controller +public class ComponentInterfaceOperationServlet extends AbstractValidationsServlet { + + private static final Logger LOGGER = LoggerFactory.getLogger(ComponentInterfaceOperationServlet.class); + private static final String START_HANDLE_REQUEST_OF = "Start handle {} request of {}"; + private static final String MODIFIER_ID_IS = "modifier id is {}"; + + private static final String FAILED_TO_UPDATE_INTERFACE_OPERATION = + "failed to update Interface Operation on component instance {}"; + private static final String UPDATE_INTERFACE_OPERATION = "Update Interface Operation on Component Instance"; + private static final String FAILED_TO_UPDATE_INTERFACE_OPERATION_WITH_ERROR = + "Failed to update Interface Operation with an error"; + private static final String INTERFACE_OPERATION_CONTENT_INVALID = "Interface Operation content is invalid - {}"; + private static final String UNSUPPORTED_COMPONENT_TYPE = "Unsupported component type {}"; + private static final String INTERFACE_OPERATION_SUCCESSFULLY_UPDATED = + "Interface Operation successfully updated on component instance with id {}"; + + private final ComponentInterfaceOperationBusinessLogic componentInterfaceOperationBusinessLogic; + + @Autowired + public ComponentInterfaceOperationServlet(final UserBusinessLogic userBusinessLogic, + final ComponentInstanceBusinessLogic componentInstanceBL, + final ComponentsUtils componentsUtils, + final ServletUtils servletUtils, + final ResourceImportManager resourceImportManager, + final ComponentInterfaceOperationBusinessLogic componentInterfaceOperationBusinessLogic) { + super(userBusinessLogic, componentInstanceBL, componentsUtils, servletUtils, resourceImportManager); + this.componentInterfaceOperationBusinessLogic = componentInterfaceOperationBusinessLogic; + } + + @PUT + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Operation(description = "Update Interface Operation", method = "PUT", + summary = "Update Interface Operation on ComponentInstance", responses = { + @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))), + @ApiResponse(responseCode = "201", description = "Update Interface Operation"), + @ApiResponse(responseCode = "403", description = "Restricted operation"), + @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")}) + @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE) + public Response updateComponentInstanceInterfaceOperation( + @Parameter(description = "valid values: resources / services", + schema = @Schema(allowableValues = { + ComponentTypeEnum.RESOURCE_PARAM_NAME, + ComponentTypeEnum.SERVICE_PARAM_NAME})) + @PathParam("componentType") final String componentType, + @Parameter(description = "Component Id") + @PathParam("componentId") String componentId, + @Parameter(description = "Component Instance Id") + @PathParam("componentInstanceId") String componentInstanceId, + @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) + throws IOException { + + LOGGER.debug(START_HANDLE_REQUEST_OF, request.getMethod(), request.getRequestURI()); + LOGGER.debug(MODIFIER_ID_IS, userId); + + final User userModifier = componentInterfaceOperationBusinessLogic.validateUser(userId); + final ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType); + if (componentTypeEnum == null) { + LOGGER.debug(UNSUPPORTED_COMPONENT_TYPE, componentType); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, componentType)); + } + + final byte[] bytes = IOUtils.toByteArray(request.getInputStream()); + if (bytes == null || bytes.length == 0) { + LOGGER.error(INTERFACE_OPERATION_CONTENT_INVALID); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + final String data = new String(bytes); + + final Optional<InterfaceDefinition> mappedInterfaceOperationData = getMappedInterfaceData(data, userModifier, componentTypeEnum); + if (mappedInterfaceOperationData.isEmpty()) { + LOGGER.error(INTERFACE_OPERATION_CONTENT_INVALID, data); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + final Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + try { + final Optional<ComponentInstance> actionResponse = componentInterfaceOperationBusinessLogic + .updateComponentInstanceInterfaceOperation(componentId, componentInstanceId, mappedInterfaceOperationData.get(), + componentTypeEnum, errorWrapper, true); + + final Response response; + if (actionResponse.isEmpty()) { + LOGGER.error(FAILED_TO_UPDATE_INTERFACE_OPERATION, componentInstanceId); + response = buildErrorResponse(errorWrapper.getInnerElement()); + } else { + LOGGER.debug(INTERFACE_OPERATION_SUCCESSFULLY_UPDATED, componentInstanceId); + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), actionResponse.get()); + } + + return response; + + } catch (final Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError(UPDATE_INTERFACE_OPERATION); + LOGGER.error(FAILED_TO_UPDATE_INTERFACE_OPERATION_WITH_ERROR, e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + private Optional<InterfaceDefinition> getMappedInterfaceData(final String inputJson, + final User user, + final ComponentTypeEnum componentTypeEnum) { + final Either<UiComponentDataTransfer, ResponseFormat> uiComponentEither = + getComponentsUtils().convertJsonToObjectUsingObjectMapper(inputJson, user, + UiComponentDataTransfer.class, AuditingActionEnum.UPDATE_RESOURCE_METADATA, componentTypeEnum); + return uiComponentEither.left().value().getInterfaces().values().stream().findFirst(); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverter.java index 8fb835e0b9..8d35517d92 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverter.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverter.java @@ -21,6 +21,7 @@ import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.INPUTS; import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.OPERATIONS; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import java.util.Collections; @@ -32,6 +33,7 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang.StringUtils; import org.openecomp.sdc.be.datatypes.elements.InputDataDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; @@ -150,63 +152,100 @@ public class InterfacesOperationsConverter { final Map<String, DataTypeDefinition> dataTypes, final boolean isAssociatedComponent, final boolean isServiceProxyInterface) { - if(MapUtils.isEmpty(interfaces)) { + if (MapUtils.isEmpty(interfaces)) { return null; } - Map<String, Object> toscaInterfaceDefinitions = new HashMap<>(); + final Map<String, Object> toscaInterfaceDefinitions = new HashMap<>(); for (InterfaceDefinition interfaceDefinition : interfaces.values()) { - ToscaInterfaceDefinition toscaInterfaceDefinition = new ToscaInterfaceDefinition(); - final String interfaceType; - if(componentInstance != null && LOCAL_INTERFACE_TYPE.equals(interfaceDefinition.getType())) { - interfaceType = DERIVED_FROM_BASE_DEFAULT + componentInstance.getSourceModelName(); - } else { - interfaceType = getInterfaceType(component, interfaceDefinition.getType()); - } - if (componentInstance == null) { - toscaInterfaceDefinition.setType(interfaceType); - } - toscaInterfaceDefinition.setType(interfaceType); - final Map<String, OperationDataDefinition> operations = interfaceDefinition.getOperations(); - Map<String, Object> toscaOperationMap = new HashMap<>(); - - String operationArtifactPath; - for (Map.Entry<String, OperationDataDefinition> operationEntry : operations.entrySet()) { - ToscaLifecycleOperationDefinition toscaOperation = new ToscaLifecycleOperationDefinition(); - if (isArtifactPresent(operationEntry)) { - operationArtifactPath = OperationArtifactUtil - .createOperationArtifactPath(component, componentInstance, operationEntry.getValue(), - isAssociatedComponent); - toscaOperation.setImplementation(operationArtifactPath); - } - toscaOperation.setDescription(operationEntry.getValue().getDescription()); - fillToscaOperationInputs(operationEntry.getValue(), dataTypes, toscaOperation, isServiceProxyInterface); + handleInterfaceOperations(component, componentInstance, dataTypes, isAssociatedComponent, + isServiceProxyInterface, toscaInterfaceDefinitions, interfaceDefinition); + } + return toscaInterfaceDefinitions; + } - toscaOperationMap.put(operationEntry.getValue().getName(), toscaOperation); - } - toscaInterfaceDefinition.setOperations(toscaOperationMap); + public Map<String, Object> getInterfacesMapFromComponentInstance(final Component component, + final ComponentInstance componentInstance, + final Map<String, DataTypeDefinition> dataTypes, + final boolean isAssociatedComponent, + final boolean isServiceProxyInterface) { + final Map<String, Object> toscaInterfaceDefinitions = new HashMap<>(); + final ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + for (final Map.Entry<String, Object> interfaceEntry : componentInstance.getInterfaces().entrySet()) { + final InterfaceDefinition interfaceDefinition = objectMapper + .convertValue(interfaceEntry.getValue(), InterfaceDefinition.class); + handleInterfaceOperations(component, componentInstance, dataTypes, isAssociatedComponent, + isServiceProxyInterface, toscaInterfaceDefinitions, interfaceDefinition); + } + return toscaInterfaceDefinitions; + } - final Map<String, Object> interfaceInputMap = createInterfaceInputMap(interfaceDefinition, dataTypes); - if (!interfaceInputMap.isEmpty()) { - toscaInterfaceDefinition.setInputs(interfaceInputMap); - } + private void handleInterfaceOperations(final Component component, + final ComponentInstance componentInstance, + final Map<String, DataTypeDefinition> dataTypes, + final boolean isAssociatedComponent, + final boolean isServiceProxyInterface, + final Map<String, Object> toscaInterfaceDefinitions, + final InterfaceDefinition interfaceDefinition) { + final String interfaceType; + if (componentInstance != null && LOCAL_INTERFACE_TYPE.equals(interfaceDefinition.getType())) { + interfaceType = DERIVED_FROM_BASE_DEFAULT + componentInstance.getSourceModelName(); + } else { + interfaceType = getInterfaceType(component, interfaceDefinition.getType()); + } + final ToscaInterfaceDefinition toscaInterfaceDefinition = new ToscaInterfaceDefinition(); + if (componentInstance == null) { + toscaInterfaceDefinition.setType(interfaceType); + } + final Map<String, OperationDataDefinition> operations = interfaceDefinition.getOperations(); + final Map<String, Object> toscaOperationMap = new HashMap<>(); + + for (final Entry<String, OperationDataDefinition> operationEntry : operations.entrySet()) { + final ToscaLifecycleOperationDefinition toscaLifecycleOperationDefinition = + new ToscaLifecycleOperationDefinition(); + handleInterfaceOperationImplementation(component, componentInstance, isAssociatedComponent, + operationEntry, + toscaLifecycleOperationDefinition); + toscaLifecycleOperationDefinition.setDescription(operationEntry.getValue().getDescription()); + fillToscaOperationInputs(operationEntry.getValue(), dataTypes, toscaLifecycleOperationDefinition, + isServiceProxyInterface); + toscaOperationMap.put(operationEntry.getValue().getName(), toscaLifecycleOperationDefinition); + } - Map<String, Object> interfaceDefAsMap = getObjectAsMap(toscaInterfaceDefinition); - if (interfaceDefAsMap.containsKey(INPUTS.getElementName())) { - handleDefaults((Map<String, Object>) interfaceDefAsMap.get(INPUTS.getElementName())); - } - Map<String, Object> operationsMap = (Map<String, Object>) interfaceDefAsMap.remove(OPERATIONS.getElementName()); - 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); - } - interfaceDefAsMap.putAll(operationsMap); - toscaInterfaceDefinitions.put(getLastPartOfName(interfaceType), interfaceDefAsMap); + toscaInterfaceDefinition.setOperations(toscaOperationMap); + final Map<String, Object> interfaceInputMap = createInterfaceInputMap(interfaceDefinition, dataTypes); + if (!interfaceInputMap.isEmpty()) { + toscaInterfaceDefinition.setInputs(interfaceInputMap); + } + final Map<String, Object> interfaceDefinitionAsMap = getObjectAsMap(toscaInterfaceDefinition); + if (interfaceDefinitionAsMap.containsKey(INPUTS.getElementName())) { + handleDefaults((Map<String, Object>) interfaceDefinitionAsMap.get(INPUTS.getElementName())); } + final Map<String, Object> operationsMap = + (Map<String, Object>) interfaceDefinitionAsMap.remove(OPERATIONS.getElementName()); - return toscaInterfaceDefinitions; + handleOperationInputValue(operationsMap, interfaceType); + + interfaceDefinitionAsMap.putAll(operationsMap); + toscaInterfaceDefinitions.put(getLastPartOfName(interfaceType), interfaceDefinitionAsMap); + } + + private void handleInterfaceOperationImplementation(final Component component, + final ComponentInstance componentInstance, + final boolean isAssociatedComponent, + final Entry<String, OperationDataDefinition> operationEntry, + final ToscaLifecycleOperationDefinition toscaOperation) { + final String operationArtifactPath; + if (isArtifactPresent(operationEntry) && StringUtils + .isNotEmpty(operationEntry.getValue().getImplementation().getArtifactName())) { + operationArtifactPath = OperationArtifactUtil + .createOperationArtifactPath(component, componentInstance, operationEntry.getValue(), + isAssociatedComponent); + toscaOperation.setImplementation(operationArtifactPath); + } else { + toscaOperation.setImplementation(operationEntry.getValue().getImplementation().getArtifactName()); + } } public void removeInterfacesWithoutOperations(final Map<String, Object> interfaceMap) { @@ -244,21 +283,6 @@ public class InterfacesOperationsConverter { return toscaInterfaceInputMap; } - private static void handleServiceProxyOperationInputValue(Map<String, Object> operationsMap, String parentKey) { - for (Map.Entry<String, Object> operationEntry : operationsMap.entrySet()) { - final Object value = operationEntry.getValue(); - final String key = operationEntry.getKey(); - if (value instanceof Map) { - if ("inputs".equals(parentKey)) { - Object defaultValue = getDefaultValue((Map<String, Object>) value); - operationsMap.put(key, defaultValue); - } else { - handleServiceProxyOperationInputValue((Map<String, Object>) value, key); - } - } - } - } - private static Object getDefaultValue(Map<String, Object> inputValueMap) { Object defaultValue = null; for (Map.Entry<String, Object> operationEntry : inputValueMap.entrySet()) { @@ -274,6 +298,22 @@ public class InterfacesOperationsConverter { return defaultValue; } + //Remove input type and copy default value directly into the proxy node template from the node type + private static void handleOperationInputValue(Map<String, Object> operationsMap, String parentKey) { + for (Map.Entry<String, Object> operationEntry : operationsMap.entrySet()) { + final Object value = operationEntry.getValue(); + final String key = operationEntry.getKey(); + if (value instanceof Map) { + if (INPUTS.getElementName().equals(parentKey)) { + Object defaultValue = getDefaultValue((Map<String, Object>) value); + operationsMap.put(key, defaultValue); + } else { + handleOperationInputValue((Map<String, Object>) value, key); + } + } + } + } + /* * workaround for : currently "defaultp" is not being converted to "default" by the relevant code in * ToscaExportHandler so, any string Map key named "defaultp" will have its named changed to "default" 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 f9125648fd..b4bf4e8d42 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 @@ -293,7 +293,7 @@ public class ToscaExportHandler { if (nodeTypesMap != null && !nodeTypesMap.isEmpty()) { toscaNode.setNode_types(nodeTypesMap); } - + createServiceSubstitutionNodeTypes(componentCache, component, toscaNode); Either<Map<String, Object>, ToscaError> proxyInterfaceTypesEither = createProxyInterfaceTypes(component); @@ -486,7 +486,7 @@ public class ToscaExportHandler { toscaMetadata.put(JsonPresentationFields.INSTANTIATION_TYPE.getPresentation(),service.getEnvironmentContext() == null ? StringUtils.EMPTY : service.getInstantiationType()); if (!isInstance) { // DE268546 - toscaMetadata.put(JsonPresentationFields.ECOMP_GENERATED_NAMING.getPresentation(),service.isEcompGeneratedNaming().toString()); + toscaMetadata.put(JsonPresentationFields.ECOMP_GENERATED_NAMING.getPresentation(),service.isEcompGeneratedNaming().toString()); toscaMetadata.put(JsonPresentationFields.ECOMP_GENERATED_NAMING.getPresentation(),service.isEcompGeneratedNaming().toString()); toscaMetadata.put(JsonPresentationFields.NAMING_POLICY.getPresentation(),service.getNamingPolicy()); } @@ -494,7 +494,7 @@ public class ToscaExportHandler { default: log.debug(NOT_SUPPORTED_COMPONENT_TYPE, component.getComponentType()); } - + for (final String key: component.getCategorySpecificMetadata().keySet()) { toscaMetadata.put(key, component.getCategorySpecificMetadata().get(key)); } @@ -904,6 +904,7 @@ public class ToscaExportHandler { addComponentInstanceInputs(dataTypes, componentInstancesInputs, instanceUniqueId, props); } + //M3[00001] - NODE TEMPLATE INTERFACES - START handleInstanceInterfaces(componentInstanceInterfaces, componentInstance, dataTypes, nodeTemplate, instanceUniqueId, component); @@ -963,29 +964,22 @@ public class ToscaExportHandler { String instanceUniqueId, Component parentComponent) { - final Map<String, Object> interfaceMap; - // we need to handle service proxy interfaces - if (isComponentOfTypeServiceProxy(componentInstance)) { - if (MapUtils.isEmpty(componentInstanceInterfaces) - || !componentInstanceInterfaces.containsKey(instanceUniqueId)) { - nodeTemplate.setInterfaces(null); - return; - } + if (MapUtils.isEmpty(componentInstanceInterfaces) + || !componentInstanceInterfaces.containsKey(instanceUniqueId)) { + nodeTemplate.setInterfaces(null); + return; + } - final List<ComponentInstanceInterface> currServiceInterfaces = - componentInstanceInterfaces.get(instanceUniqueId); + final List<ComponentInstanceInterface> currServiceInterfaces = + componentInstanceInterfaces.get(instanceUniqueId); - final Map<String, InterfaceDefinition> tmpInterfaces = new HashMap<>(); - currServiceInterfaces.forEach(instInterface -> tmpInterfaces.put(instInterface - .getUniqueId(), instInterface)); + final Map<String, InterfaceDefinition> tmpInterfaces = new HashMap<>(); + currServiceInterfaces.forEach(instInterface -> tmpInterfaces.put(instInterface + .getUniqueId(), instInterface)); + + final Map<String, Object> interfaceMap = interfacesOperationsConverter + .getInterfacesMap(parentComponent, componentInstance, tmpInterfaces, dataTypes, isComponentOfTypeServiceProxy(componentInstance), isComponentOfTypeServiceProxy(componentInstance)); - interfaceMap = interfacesOperationsConverter - .getInterfacesMap(parentComponent, componentInstance, tmpInterfaces, dataTypes, true, true); - } else { - interfaceMap = - getComponentInstanceInterfaceInstances(componentInstanceInterfaces, - componentInstance, instanceUniqueId); - } interfacesOperationsConverter.removeInterfacesWithoutOperations(interfaceMap); nodeTemplate.setInterfaces(MapUtils.isEmpty(interfaceMap) ? null : interfaceMap); } @@ -1210,7 +1204,7 @@ public class ToscaExportHandler { return Either.left(nodeTypesMap); } - + private void createServiceSubstitutionNodeTypes(final Map<String, Component> componentCache, final Component container, final ToscaTemplate toscaNode) { final List<ComponentInstance> componentInstances = container.getComponentInstances(); @@ -1226,11 +1220,11 @@ public class ToscaExportHandler { final Map<String, ToscaNodeType> nodeTypes = toscaNode.getNode_types() == null ? new HashMap<>() : toscaNode.getNode_types(); convertInterfaceNodeType(new HashMap<>(), componentCache.get(inst.getSourceModelUid()), toscaNode, nodeTypes, true); } - } + } } private ToscaNodeType createProxyNodeType(Map<String, Component> componentCache, Component origComponent, - Component proxyComponent, ComponentInstance instance) { + Component proxyComponent, ComponentInstance componentInstance) { ToscaNodeType toscaNodeType = new ToscaNodeType(); String derivedFrom = ((Resource) origComponent).getToscaResourceName(); @@ -1241,25 +1235,32 @@ public class ToscaExportHandler { } Map<String, DataTypeDefinition> dataTypes = dataTypesEither.left().value(); Map<String, ToscaCapability> capabilities = this.capabilityRequirementConverter - .convertProxyCapabilities(componentCache, instance, dataTypes); + .convertProxyCapabilities(componentCache, componentInstance, dataTypes); if (MapUtils.isNotEmpty(capabilities)) { toscaNodeType.setCapabilities(capabilities); } List<Map<String, ToscaRequirement>> proxyNodeTypeRequirements = this.capabilityRequirementConverter - .convertProxyRequirements(componentCache, instance); + .convertProxyRequirements(componentCache, componentInstance); if (CollectionUtils.isNotEmpty(proxyNodeTypeRequirements)) { toscaNodeType.setRequirements(proxyNodeTypeRequirements); } Optional<Map<String, ToscaProperty>> proxyProperties = getProxyNodeTypeProperties(proxyComponent, dataTypes); proxyProperties.ifPresent(toscaNodeType::setProperties); - Optional<Map<String, Object>> proxyInterfaces = getProxyNodeTypeInterfaces(proxyComponent, dataTypes); - if (proxyInterfaces.isPresent()) { - final Map<String, Object> interfaceMap = proxyInterfaces.get(); - interfacesOperationsConverter.removeInterfacesWithoutOperations(interfaceMap); - toscaNodeType.setInterfaces(MapUtils.isEmpty(interfaceMap) ? null : interfaceMap); + Map<String, Object> interfaceMap = new HashMap<>(); + if (MapUtils.isEmpty(componentInstance.getInterfaces())) { + final Optional<Map<String, Object>> proxyInterfaces = getProxyNodeTypeInterfaces(proxyComponent, dataTypes); + if (proxyInterfaces.isPresent()) { + interfaceMap = proxyInterfaces.get(); + } + } else { + interfaceMap = interfacesOperationsConverter + .getInterfacesMapFromComponentInstance(proxyComponent, componentInstance, dataTypes, false, false); + } + interfacesOperationsConverter.removeInterfacesWithoutOperations(interfaceMap); + toscaNodeType.setInterfaces(MapUtils.isEmpty(interfaceMap) ? null : interfaceMap); return toscaNodeType; } |