diff options
8 files changed, 474 insertions, 104 deletions
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 index 3ac8ce3562..a10bae9c1e 100644 --- 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 @@ -37,6 +37,7 @@ import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.ListUtils; import org.apache.commons.collections.MapUtils; import org.openecomp.sdc.be.components.impl.exceptions.BusinessLogicException; import org.openecomp.sdc.be.components.validation.ComponentValidations; @@ -306,6 +307,84 @@ public class ComponentInterfaceOperationBusinessLogic extends BaseBusinessLogic return Optional.of(component); } + public Optional<ComponentInstance> createComponentInstanceInterfaceOperation(String componentId, String componentInstanceId, + InterfaceDefinition interfaceDefinition, + ComponentTypeEnum componentTypeEnum, + Wrapper<ResponseFormat> errorWrapper, final boolean shouldLock) + throws BusinessLogicException { + ResponseFormat responseFormat; + final Component component = getComponent(componentId); + final Optional<ComponentInstance> componentInstanceOptional = componentValidations.getComponentInstance(component, componentInstanceId); + if (componentInstanceOptional.isEmpty()) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND); + LOGGER.debug("Failed to find 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 String interfaceKey = interfaceDefinition.getType(); + interfaceDefinition.setUniqueId(interfaceKey); + interfaceDefinition.setToscaResourceName(interfaceKey); + interfaceDefinition.setUserCreated(true); + + final Optional<OperationDataDefinition> optionalOperationDataDefinition = interfaceDefinition.getOperations().values().stream().findFirst(); + if (optionalOperationDataDefinition.isEmpty()) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND, interfaceKey); + LOGGER.debug("Failed to find interface operation on interface being added {}, error: {}", interfaceKey, responseFormat); + errorWrapper.setInnerElement(responseFormat); + return Optional.empty(); + } + + final OperationDataDefinition updatedOperationDataDefinition = optionalOperationDataDefinition.get(); + updatedOperationDataDefinition.setUniqueId(UUID.randomUUID().toString()); + updatedOperationDataDefinition.getImplementation() + .setArtifactName(generateArtifactName(updatedOperationDataDefinition.getImplementation().getArtifactName())); + + List<ComponentInstanceInterface> componentInstanceInterfaceList = componentInstancesInterfaceMap.get(componentInstanceId); + componentInstanceInterfaceList = CollectionUtils.isEmpty(componentInstanceInterfaceList) ? new ArrayList<>() : componentInstanceInterfaceList; + Optional<ComponentInstanceInterface> componentInstanceInterface = + componentInstanceInterfaceList.stream().filter(instInterface -> instInterface.getInterfaceId().equals(interfaceKey)).findFirst(); + + if (componentInstanceInterface.isEmpty()) { + componentInstanceInterfaceList.add(new ComponentInstanceInterface(interfaceKey, interfaceDefinition)); + componentInstanceOptional.get().addInterface(interfaceKey, interfaceDefinition); + } else { + componentInstanceInterface.get().getOperations().put(updatedOperationDataDefinition.getName(), updatedOperationDataDefinition); + } + + boolean wasLocked = false; + try { + if (shouldLock) { + lockComponent(componentId, component, UPDATE_INTERFACE_OPERATION_ON_COMPONENT_INSTANCE); + wasLocked = true; + } + 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(); + } + 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 Optional<Component> createInterfaceOperationInResource(final String componentId, final InterfaceDefinition interfaceDefinition, final ComponentTypeEnum componentTypeEnum, final Wrapper<ResponseFormat> errorWrapper, final boolean shouldLock) 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 edbad79e14..ae94d9803d 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 @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.openecomp.sdc.be.components.utils; import java.util.ArrayList; @@ -31,6 +32,7 @@ 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.ComponentInstanceInterface; import org.openecomp.sdc.be.model.InputDefinition; import org.openecomp.sdc.be.model.InterfaceDefinition; import org.openecomp.sdc.be.model.Operation; 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 index fbb7d0b0ac..1e68b0f431 100644 --- 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 @@ -18,6 +18,7 @@ * SPDX-License-Identifier: Apache-2.0 * ============LICENSE_END========================================================= */ + package org.openecomp.sdc.be.servlets; import static org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum.RESOURCE; @@ -87,7 +88,8 @@ public class ComponentInterfaceOperationServlet extends AbstractValidationsServl 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 static final String INTERFACE_OPERATION_SUCCESSFULLY_UPDATED = + "Interface Operation successfully updated on component instance with id {}"; private final ComponentInterfaceOperationBusinessLogic componentInterfaceOperationBusinessLogic; @Autowired @@ -206,6 +208,62 @@ public class ComponentInterfaceOperationServlet extends AbstractValidationsServl } @POST + @Path("/{componentType}/{componentId}/componentInstance/{componentInstanceId}/interfaceOperation") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Operation(description = "Create Interface Operation", method = "POST", summary = "Create Interface Operation on ComponentInstance", responses = { + @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))), + @ApiResponse(responseCode = "201", description = "Create Interface Operation"), + @ApiResponse(responseCode = "403", description = "Restricted operation"), + @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")}) + @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE) + public Response createComponentInstanceInterfaceOperation( + @Parameter(description = "valid values: resources / services", schema = @Schema(allowableValues = {ComponentTypeEnum.RESOURCE_PARAM_NAME, + ComponentTypeEnum.SERVICE_PARAM_NAME})) @PathParam("componentType") 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()); + userId = ValidationUtils.sanitizeInputString(userId); + componentType = ValidationUtils.sanitizeInputString(componentType); + componentInstanceId = ValidationUtils.sanitizeInputString(componentInstanceId); + 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, "content is empty"); + 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.createComponentInstanceInterfaceOperation( + componentId, componentInstanceId, mappedInterfaceOperationData.get(), componentTypeEnum, errorWrapper, true); + if (actionResponse.isEmpty()) { + LOGGER.error(FAILED_TO_UPDATE_INTERFACE_OPERATION, componentInstanceId); + return buildErrorResponse(errorWrapper.getInnerElement()); + } else { + LOGGER.debug(INTERFACE_OPERATION_SUCCESSFULLY_UPDATED, componentInstanceId); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), actionResponse.get()); + } + } 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)); + } + } + + @POST @Path("/{componentType}/{componentId}/resource/interfaceOperation") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogicTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogicTest.java index b3f6024a9b..1dd7f40730 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogicTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogicTest.java @@ -26,6 +26,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import fj.data.Either; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -418,6 +419,126 @@ class ComponentInterfaceOperationBusinessLogicTest extends BaseBusinessLogicMock assertThat(result).isPresent(); } + @Test + void createComponentInstanceInterfaceOperationTest() throws BusinessLogicException { + final String componentId = component.getUniqueId(); + final String componentInstanceId = componentInstance.getUniqueId(); + final InterfaceDefinition interfaceDefinition = new InterfaceDefinition(); + interfaceDefinition.setUniqueId(UUID.randomUUID().toString()); + interfaceDefinition.setType("tosca.interfaces.node.lifecycle.Standard"); + final Map<String, OperationDataDefinition> operations = new HashMap<>(); + final OperationDataDefinition operationDataDefinition = new OperationDataDefinition(); + operationDataDefinition.setUniqueId(UUID.randomUUID().toString()); + final ArtifactDataDefinition artifactDataDefinition = new ArtifactDataDefinition(); + artifactDataDefinition.setArtifactName("EO Implementation info"); + operationDataDefinition.setImplementation(artifactDataDefinition); + operations.put("configure", operationDataDefinition); + interfaceDefinition.setOperations(operations ); + + Map<String, List<ComponentInstanceInterface>> componentInstancesInterfacesMap = new HashMap<>(); + componentInstancesInterfacesMap.put(componentInstanceId, new ArrayList<>()); + componentInstance.setInterfaces( + (Map<String, Object>) new HashMap<>().put(componentInstanceId, interfaceDefinition)); + component.setComponentInstances(Collections.singletonList(componentInstance)); + + when(toscaOperationFacade.getToscaElement(componentId)).thenReturn(Either.left(component)); + when(componentValidations.getComponentInstance(component, componentInstanceId)) + .thenReturn(Optional.of(componentInstance)); + when(graphLockOperation.lockComponent(componentId, NodeTypeEnum.Service)) + .thenReturn(StorageOperationStatus.OK); + when(toscaOperationFacade.updateComponentInstanceInterfaces(component, componentInstanceId)) + .thenReturn(StorageOperationStatus.OK); + when(janusGraphDao.commit()).thenReturn(JanusGraphOperationStatus.OK); + when(graphLockOperation.unlockComponent(componentId, NodeTypeEnum.Service)) + .thenReturn(StorageOperationStatus.OK); + + final Optional<ComponentInstance> result = componentInterfaceOperationBusinessLogic + .createComponentInstanceInterfaceOperation(componentId, componentInstanceId, interfaceDefinition, + ComponentTypeEnum.SERVICE, new Wrapper<>(), true); + assertThat(result).isPresent(); + } + + @Test + void createComponentInstanceInterfaceOperationTestUpdateFail() throws BusinessLogicException { + final String componentId = component.getUniqueId(); + final String componentInstanceId = componentInstance.getUniqueId(); + final InterfaceDefinition interfaceDefinition = new InterfaceDefinition(); + interfaceDefinition.setUniqueId(UUID.randomUUID().toString()); + interfaceDefinition.setType("tosca.interfaces.node.lifecycle.Standard"); + final Map<String, OperationDataDefinition> operations = new HashMap<>(); + final OperationDataDefinition operationDataDefinition = new OperationDataDefinition(); + operationDataDefinition.setUniqueId(UUID.randomUUID().toString()); + final ArtifactDataDefinition artifactDataDefinition = new ArtifactDataDefinition(); + artifactDataDefinition.setArtifactName("EO Implementation info"); + operationDataDefinition.setImplementation(artifactDataDefinition); + operations.put("configure", operationDataDefinition); + interfaceDefinition.setOperations(operations ); + + Map<String, List<ComponentInstanceInterface>> componentInstancesInterfacesMap = new HashMap<>(); + componentInstancesInterfacesMap.put(componentInstanceId, new ArrayList<>()); + componentInstance.setInterfaces( + (Map<String, Object>) new HashMap<>().put(componentInstanceId, interfaceDefinition)); + component.setComponentInstances(Collections.singletonList(componentInstance)); + + when(toscaOperationFacade.getToscaElement(componentId)).thenReturn(Either.left(component)); + when(componentValidations.getComponentInstance(component, componentInstanceId)) + .thenReturn(Optional.of(componentInstance)); + when(graphLockOperation.lockComponent(componentId, NodeTypeEnum.Service)) + .thenReturn(StorageOperationStatus.OK); + when(toscaOperationFacade.updateComponentInstanceInterfaces(component, componentInstanceId)) + .thenReturn(StorageOperationStatus.GENERAL_ERROR); + when(janusGraphDao.rollback()).thenReturn(JanusGraphOperationStatus.OK); + when(graphLockOperation.unlockComponent(componentId, NodeTypeEnum.Service)) + .thenReturn(StorageOperationStatus.OK); + + final Optional<ComponentInstance> result = componentInterfaceOperationBusinessLogic + .createComponentInstanceInterfaceOperation(componentId, componentInstanceId, interfaceDefinition, + ComponentTypeEnum.SERVICE, new Wrapper<>(), true); + assertThat(result).isEmpty(); + } + + @Test + void createComponentInstanceInterfaceOperationTestNoInstances() throws BusinessLogicException { + final String componentId = component.getUniqueId(); + final String componentInstanceId = componentInstance.getUniqueId(); + final InterfaceDefinition interfaceDefinition = new InterfaceDefinition(); + interfaceDefinition.setUniqueId(UUID.randomUUID().toString()); + interfaceDefinition.setType("tosca.interfaces.node.lifecycle.Standard"); + + component.setComponentInstances(Collections.singletonList(componentInstance)); + + when(toscaOperationFacade.getToscaElement(componentId)).thenReturn(Either.left(component)); + + final Optional<ComponentInstance> result = componentInterfaceOperationBusinessLogic + .createComponentInstanceInterfaceOperation(componentId, componentInstanceId, interfaceDefinition, + ComponentTypeEnum.SERVICE, new Wrapper<>(), true); + assertThat(result).isEmpty(); + } + + @Test + void createComponentInstanceInterfaceOperationTestNoOperations() throws BusinessLogicException { + final String componentId = component.getUniqueId(); + final String componentInstanceId = componentInstance.getUniqueId(); + final InterfaceDefinition interfaceDefinition = new InterfaceDefinition(); + interfaceDefinition.setUniqueId(UUID.randomUUID().toString()); + interfaceDefinition.setType("tosca.interfaces.node.lifecycle.Standard"); + + Map<String, List<ComponentInstanceInterface>> componentInstancesInterfacesMap = new HashMap<>(); + componentInstancesInterfacesMap.put(componentInstanceId, new ArrayList<>()); + componentInstance.setInterfaces( + (Map<String, Object>) new HashMap<>().put(componentInstanceId, interfaceDefinition)); + component.setComponentInstances(Collections.singletonList(componentInstance)); + + when(toscaOperationFacade.getToscaElement(componentId)).thenReturn(Either.left(component)); + when(componentValidations.getComponentInstance(component, componentInstanceId)) + .thenReturn(Optional.of(componentInstance)); + + final Optional<ComponentInstance> result = componentInterfaceOperationBusinessLogic + .createComponentInstanceInterfaceOperation(componentId, componentInstanceId, interfaceDefinition, + ComponentTypeEnum.SERVICE, new Wrapper<>(), true); + assertThat(result).isEmpty(); + } + private void initComponentData() { try { component = new Service(); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperation.java index f75c7a6b06..0b296757cf 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperation.java @@ -17,6 +17,7 @@ * limitations under the License. * ============LICENSE_END========================================================= */ + package org.openecomp.sdc.be.model.jsonjanusgraph.operations; import fj.data.Either; @@ -134,7 +135,8 @@ public class NodeTemplateOperation extends BaseOperation { static final String HEAT_VF_ENV_NAME = "VfHeatEnv"; static final String HEAT_ENV_SUFFIX = "env"; private static final String FAILED_TO_FETCH_CONTAINER_VERTEX_ERROR = "Failed to fetch container vertex {} error {}"; - private static final String FAILED_TO_UPDATE_TOPOLOGY_TEMPLATE_WITH_NEW_COMPONENT_INSTANCE = "Failed to update topology template {} with new component instance {}. "; + private static final String FAILED_TO_UPDATE_TOPOLOGY_TEMPLATE_WITH_NEW_COMPONENT_INSTANCE = + "Failed to update topology template {} with new component instance {}. "; private static final String ARTIFACT_PLACEHOLDER_TYPE = "type"; private static final String ARTIFACT_PLACEHOLDER_DISPLAY_NAME = "displayName"; private static final Object ARTIFACT_PLACEHOLDER_DESCRIPTION = "description"; @@ -669,31 +671,35 @@ public class NodeTemplateOperation extends BaseOperation { if (composition != null) { Map<String, RelationshipInstDataDefinition> relations = composition.getRelations(); if (MapUtils.isNotEmpty(relations)) { - Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capResult = fetchContainerCalculatedCapability( - containerV, EdgeLabelEnum.CALCULATED_CAPABILITIES); + Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capResult = + fetchContainerCalculatedCapability( + containerV, EdgeLabelEnum.CALCULATED_CAPABILITIES); if (capResult.isRight()) { return capResult.right().value(); } Map<String, MapListCapabilityDataDefinition> calculatedCapabilty = capResult.left().value().getRight(); - Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capFullResult = fetchContainerCalculatedCapability( - containerV, EdgeLabelEnum.FULLFILLED_CAPABILITIES); + Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capFullResult = + fetchContainerCalculatedCapability( + containerV, EdgeLabelEnum.FULLFILLED_CAPABILITIES); if (capFullResult.isRight()) { return capFullResult.right().value(); } Map<String, MapListCapabilityDataDefinition> fullFilledCapabilty = capFullResult.left().value().getRight(); - Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqResult = fetchContainerCalculatedRequirement( - containerV, EdgeLabelEnum.CALCULATED_REQUIREMENTS); + Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqResult = + fetchContainerCalculatedRequirement( + containerV, EdgeLabelEnum.CALCULATED_REQUIREMENTS); if (reqResult.isRight()) { return reqResult.right().value(); } Map<String, MapListRequirementDataDefinition> calculatedRequirement = reqResult.left().value().getRight(); - Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqFullResult = fetchContainerCalculatedRequirement( - containerV, EdgeLabelEnum.FULLFILLED_REQUIREMENTS); + Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqFullResult = + fetchContainerCalculatedRequirement( + containerV, EdgeLabelEnum.FULLFILLED_REQUIREMENTS); if (reqResult.isRight()) { return reqResult.right().value(); } @@ -1588,26 +1594,30 @@ public class NodeTemplateOperation extends BaseOperation { return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(error)); } GraphVertex containerV = containerVEither.left().value(); - Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capResult = fetchContainerCalculatedCapability( - containerV, EdgeLabelEnum.CALCULATED_CAPABILITIES); + Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capResult = + fetchContainerCalculatedCapability( + containerV, EdgeLabelEnum.CALCULATED_CAPABILITIES); if (capResult.isRight()) { return Either.right(capResult.right().value()); } Map<String, MapListCapabilityDataDefinition> calculatedCapabilty = capResult.left().value().getRight(); - Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capFullResult = fetchContainerCalculatedCapability( - containerV, EdgeLabelEnum.FULLFILLED_CAPABILITIES); + Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capFullResult = + fetchContainerCalculatedCapability( + containerV, EdgeLabelEnum.FULLFILLED_CAPABILITIES); if (capResult.isRight()) { return Either.right(capResult.right().value()); } Map<String, MapListCapabilityDataDefinition> fullFilledCapabilty = capFullResult.left().value().getRight(); - Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqResult = fetchContainerCalculatedRequirement( - containerV, EdgeLabelEnum.CALCULATED_REQUIREMENTS); + Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqResult = + fetchContainerCalculatedRequirement( + containerV, EdgeLabelEnum.CALCULATED_REQUIREMENTS); if (reqResult.isRight()) { return Either.right(reqResult.right().value()); } Map<String, MapListRequirementDataDefinition> calculatedRequirement = reqResult.left().value().getRight(); - Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqFullResult = fetchContainerCalculatedRequirement( - containerV, EdgeLabelEnum.FULLFILLED_REQUIREMENTS); + Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqFullResult = + fetchContainerCalculatedRequirement( + containerV, EdgeLabelEnum.FULLFILLED_REQUIREMENTS); if (reqResult.isRight()) { return Either.right(reqResult.right().value()); } @@ -1823,26 +1833,30 @@ public class NodeTemplateOperation extends BaseOperation { } Map<String, RelationshipInstDataDefinition> relations = compositionDataDefinition.getRelations(); List<CapabilityRequirementRelationship> relationPairList = requirementDef.getRelationships(); - Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capResult = fetchContainerCalculatedCapability( - containerV, EdgeLabelEnum.CALCULATED_CAPABILITIES); + Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capResult = + fetchContainerCalculatedCapability( + containerV, EdgeLabelEnum.CALCULATED_CAPABILITIES); if (capResult.isRight()) { return Either.right(capResult.right().value()); } Map<String, MapListCapabilityDataDefinition> calculatedCapability = capResult.left().value().getRight(); - Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capFullResult = fetchContainerCalculatedCapability( - containerV, EdgeLabelEnum.FULLFILLED_CAPABILITIES); + Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capFullResult = + fetchContainerCalculatedCapability( + containerV, EdgeLabelEnum.FULLFILLED_CAPABILITIES); if (capResult.isRight()) { return Either.right(capResult.right().value()); } Map<String, MapListCapabilityDataDefinition> fulfilledCapability = capFullResult.left().value().getRight(); - Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqResult = fetchContainerCalculatedRequirement( - containerV, EdgeLabelEnum.CALCULATED_REQUIREMENTS); + Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqResult = + fetchContainerCalculatedRequirement( + containerV, EdgeLabelEnum.CALCULATED_REQUIREMENTS); if (reqResult.isRight()) { return Either.right(reqResult.right().value()); } Map<String, MapListRequirementDataDefinition> calculatedRequirement = reqResult.left().value().getRight(); - Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqFullResult = fetchContainerCalculatedRequirement( - containerV, EdgeLabelEnum.FULLFILLED_REQUIREMENTS); + Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqFullResult = + fetchContainerCalculatedRequirement( + containerV, EdgeLabelEnum.FULLFILLED_REQUIREMENTS); if (reqResult.isRight()) { return Either.right(reqResult.right().value()); } @@ -2237,8 +2251,9 @@ public class NodeTemplateOperation extends BaseOperation { private Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> fetchContainerCalculatedCapability( GraphVertex containerV, EdgeLabelEnum capLabel) { - Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, JanusGraphOperationStatus> calculatedCapabiltyEither = getDataAndVertexFromGraph( - containerV, capLabel); + Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, JanusGraphOperationStatus> calculatedCapabiltyEither = + getDataAndVertexFromGraph( + containerV, capLabel); if (calculatedCapabiltyEither.isRight()) { JanusGraphOperationStatus error = calculatedCapabiltyEither.right().value(); CommonUtility @@ -2251,8 +2266,9 @@ public class NodeTemplateOperation extends BaseOperation { private Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> fetchContainerCalculatedRequirement( GraphVertex containerV, EdgeLabelEnum reqLabel) { - Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, JanusGraphOperationStatus> calculatedRequirementEither = getDataAndVertexFromGraph( - containerV, reqLabel); + Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, JanusGraphOperationStatus> calculatedRequirementEither = + getDataAndVertexFromGraph( + containerV, reqLabel); if (calculatedRequirementEither.isRight()) { JanusGraphOperationStatus error = calculatedRequirementEither.right().value(); CommonUtility diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java index 951dc5aaed..b6339e85ec 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java @@ -17,13 +17,39 @@ * limitations under the License. * ============LICENSE_END========================================================= */ + package org.openecomp.sdc.be.model.jsonjanusgraph.operations; +import static java.util.Objects.requireNonNull; +import static org.apache.commons.collections.CollectionUtils.isEmpty; +import static org.apache.commons.collections.CollectionUtils.isNotEmpty; +import static org.janusgraph.core.attribute.Text.REGEX; +import static org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum.TOPOLOGY_TEMPLATE; + import com.vdurmont.semver4j.Semver; import com.vdurmont.semver4j.Semver.SemverType; import fj.data.Either; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; +import java.util.function.BiPredicate; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; @@ -113,32 +139,6 @@ import org.openecomp.sdc.common.log.wrappers.Logger; import org.openecomp.sdc.common.util.ValidationUtils; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.TreeSet; -import java.util.function.BiPredicate; -import java.util.stream.Collectors; - -import static java.util.Objects.requireNonNull; -import static org.apache.commons.collections.CollectionUtils.isEmpty; -import static org.apache.commons.collections.CollectionUtils.isNotEmpty; -import static org.janusgraph.core.attribute.Text.REGEX; -import static org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum.TOPOLOGY_TEMPLATE; - @org.springframework.stereotype.Component("tosca-operation-facade") public class ToscaOperationFacade { @@ -146,9 +146,11 @@ public class ToscaOperationFacade { public static final String PROXY_SUFFIX = "_proxy"; // region - Fields private static final String COULDNT_FETCH_A_COMPONENT_WITH_AND_UNIQUE_ID_ERROR = "Couldn't fetch a component with and UniqueId {}, error: {}"; - private static final String FAILED_TO_FIND_RECENTLY_ADDED_PROPERTY_ON_THE_RESOURCE_STATUS_IS = "Failed to find recently added property {} on the resource {}. Status is {}. "; + private static final String FAILED_TO_FIND_RECENTLY_ADDED_PROPERTY_ON_THE_RESOURCE_STATUS_IS = + "Failed to find recently added property {} on the resource {}. Status is {}. "; private static final String FAILED_TO_GET_UPDATED_RESOURCE_STATUS_IS = "Failed to get updated resource {}. Status is {}. "; - private static final String FAILED_TO_ADD_THE_PROPERTY_TO_THE_RESOURCE_STATUS_IS = "Failed to add the property {} to the resource {}. Status is {}. "; + private static final String FAILED_TO_ADD_THE_PROPERTY_TO_THE_RESOURCE_STATUS_IS = + "Failed to add the property {} to the resource {}. Status is {}. "; private static final String SERVICE = "service"; private static final String VF = "VF"; private static final String NOT_SUPPORTED_COMPONENT_TYPE = "Not supported component type {}"; @@ -2532,7 +2534,7 @@ public class ToscaOperationFacade { } Component component = latestVersionList.size() == 1 ? latestVersionList.get(0) : latestVersionList.stream().max((c1, c2) -> Double.compare(Double.parseDouble(c1.getVersion()), Double.parseDouble(c2.getVersion()))) - .get(); + .get(); return Either.left(component); } diff --git a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts index 82afb0a3e7..4ada629cea 100644 --- a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts +++ b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts @@ -26,7 +26,7 @@ import {ISdcConfig, SdcConfigToken} from "app/ng2/config/sdc-config.config"; import {TranslateService} from "app/ng2/shared/translator/translate.service"; import {IModalButtonComponent, SdcUiServices} from 'onap-ui-angular'; import {ModalComponent} from 'app/ng2/components/ui/modal/modal.component'; - +import {ResourceType, ComponentType} from "app/utils"; import {ModalService} from 'app/ng2/services/modal.service'; import { ArtifactModel, @@ -238,9 +238,13 @@ export class InterfaceDefinitionComponent { } onInstanceSelectedUpdate = (instance: any) => { + this.interfaces = []; this.selectedInstanceData = instance; if (instance.name != "SELF") { - this.disableFlag = true; + this.disableFlag = !this.isAllowAddOperation(instance.originType); + if (!instance.interfaces) { + return; + } let newInterfaces : InterfaceModel[] = []; if (instance.interfaces instanceof Array) { instance.interfaces.forEach(result => { @@ -252,6 +256,8 @@ export class InterfaceDefinitionComponent { } else if (!_.isEmpty(result.operations)) { interfaceObj.operations = []; Object.keys(result.operations).forEach(name => { + result.operations[name].interfaceId = result.type; + result.operations[name].interfaceType = result.type; interfaceObj.operations.push(result.operations[name]); }); } @@ -268,6 +274,8 @@ export class InterfaceDefinitionComponent { } else if (!_.isEmpty(obj.operations)) { interfaceObj.operations = []; Object.keys(obj.operations).forEach(name => { + obj.operations[name].interfaceId = key; + obj.operations[name].interfaceType = key; interfaceObj.operations.push(obj.operations[name]); }); } @@ -276,11 +284,19 @@ export class InterfaceDefinitionComponent { } this.interfaces = newInterfaces.map((interf) => new UIInterfaceModel(interf)); } else { + this.disableFlag = true; this.interfaces = this.serviceInterfaces.map((interf) => new UIInterfaceModel(interf)); } this.sortInterfaces(); } + isAllowAddOperation(originType: string): boolean { + if (originType && (originType === ResourceType.VFC || originType === ResourceType.CP || originType === ResourceType.VL)){ + return true; + } + return false; + } + initInterfaces(interfaces: InterfaceModel[]): void { if (interfaces) { this.interfaces = interfaces.map((interf) => new UIInterfaceModel(interf)); @@ -296,9 +312,6 @@ export class InterfaceDefinitionComponent { if(this.readonly) { return disable; } - if (this.component.isService()) { - return disable; - } const validMilestoneActivities = this.modalInstance.instance.dynamicContent.instance.validMilestoneActivities; const validMilestoneFilters = this.modalInstance.instance.dynamicContent.instance.validMilestoneFilters; if (!validMilestoneActivities || !validMilestoneFilters) { @@ -376,53 +389,106 @@ export class InterfaceDefinitionComponent { if (timeout != null) { operationToUpdate.implementation.timeout = timeout; } - this.componentServiceNg2.updateComponentInterfaceOperation(this.component.uniqueId, operationToUpdate) - .subscribe((newOperation: InterfaceOperationModel) => { - let oldOpIndex; - let oldInterf; - this.interfaces.forEach(interf => { - interf.operations.forEach(op => { - if (op.uniqueId === newOperation.uniqueId) { - oldInterf = interf; - oldOpIndex = interf.operations.findIndex((el) => el.uniqueId === op.uniqueId); - } + if (this.component.componentType === ComponentType.SERVICE) { + this.topologyTemplateService.updateComponentInstanceInterfaceOperation(this.component.uniqueId, this.component.componentType, this.selectedInstanceData.uniqueId, operationToUpdate) + .subscribe((res) => { + const interf: InterfaceModel = _.find(res.interfaces, interf => interf.type === operationToUpdate.interfaceType); + const newOp: OperationModel = _.find(interf.operations, op => op.name === operationToUpdate.name); + let newOperation = new InterfaceOperationModel({ + ...newOp, + interfaceType: interf.type, + interfaceId: interf.uniqueId, + }) + let oldOpIndex; + let oldInterf; + this.interfaces.forEach(interf => { + interf.operations.forEach(op => { + if (op.uniqueId === newOperation.uniqueId) { + oldInterf = interf; + oldOpIndex = interf.operations.findIndex((el) => el.uniqueId === op.uniqueId); + } + }); }); + oldInterf.operations.splice(oldOpIndex, 1); + oldInterf.operations.push(new InterfaceOperationModel(newOperation)); + }, () => { + this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false; + }, () => { + this.sortInterfaces(); + this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false; + this.modalServiceNg2.closeCurrentModal(); }); - oldInterf.operations.splice(oldOpIndex, 1); - oldInterf.operations.push(new InterfaceOperationModel(newOperation)); - }, error => { - this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false; - }, () => { - this.sortInterfaces(); - this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false; - this.modalServiceNg2.closeCurrentModal(); - }); + } else { + this.componentServiceNg2.updateComponentInterfaceOperation(this.component.uniqueId, operationToUpdate) + .subscribe((newOperation: InterfaceOperationModel) => { + let oldOpIndex; + let oldInterf; + this.interfaces.forEach(interf => { + interf.operations.forEach(op => { + if (op.uniqueId === newOperation.uniqueId) { + oldInterf = interf; + oldOpIndex = interf.operations.findIndex((el) => el.uniqueId === op.uniqueId); + } + }); + }); + oldInterf.operations.splice(oldOpIndex, 1); + oldInterf.operations.push(new InterfaceOperationModel(newOperation)); + }, () => { + this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false; + }, () => { + this.sortInterfaces(); + this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false; + this.modalServiceNg2.closeCurrentModal(); + }); + } } private createOperationCallback(): void { this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = true; const operationToUpdate = this.modalInstance.instance.dynamicContent.instance.operationToUpdate; - console.log('createOperationCallback', operationToUpdate); - console.log('this.component', this.component); - this.componentServiceNg2.createComponentInterfaceOperation(this.component.uniqueId, this.component.getTypeUrl(), operationToUpdate) - .subscribe((newOperation: InterfaceOperationModel) => { - const foundInterface = this.interfaces.find(value => value.type === newOperation.interfaceType); - if (foundInterface) { - foundInterface.operations.push(new UIOperationModel(new OperationModel(newOperation))); - } else { - const uiInterfaceModel = new UIInterfaceModel(); - uiInterfaceModel.type = newOperation.interfaceType; - uiInterfaceModel.uniqueId = newOperation.interfaceType; - uiInterfaceModel.operations = []; - uiInterfaceModel.operations.push(new UIOperationModel(new OperationModel(newOperation))); - this.interfaces.push(uiInterfaceModel); - } - }, error => { - this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false; - }, () => { - this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false; - this.modalServiceNg2.closeCurrentModal(); - }); + if (this.component.componentType === ComponentType.SERVICE) { + this.topologyTemplateService.createComponentInstanceInterfaceOperation(this.component.uniqueId, this.selectedInstanceData.uniqueId, operationToUpdate) + .subscribe((newOperation: InterfaceOperationModel) => { + const foundInterface = this.interfaces.find(value => value.type === newOperation.interfaceType); + if (foundInterface) { + foundInterface.operations.push(new UIOperationModel(new OperationModel(newOperation))); + } else { + const uiInterfaceModel = new UIInterfaceModel(); + uiInterfaceModel.type = newOperation.interfaceType; + uiInterfaceModel.uniqueId = newOperation.interfaceType; + uiInterfaceModel.operations = []; + uiInterfaceModel.operations.push(new UIOperationModel(new OperationModel(newOperation))); + this.interfaces.push(uiInterfaceModel); + } + }, () => { + this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false; + this.modalServiceNg2.closeCurrentModal(); + }, () => { + this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false; + this.modalServiceNg2.closeCurrentModal(); + }); + } else { + this.componentServiceNg2.createComponentInterfaceOperation(this.component.uniqueId, this.component.getTypeUrl(), operationToUpdate) + .subscribe((newOperation: InterfaceOperationModel) => { + const foundInterface = this.interfaces.find(value => value.type === newOperation.interfaceType); + if (foundInterface) { + foundInterface.operations.push(new UIOperationModel(new OperationModel(newOperation))); + } else { + const uiInterfaceModel = new UIInterfaceModel(); + uiInterfaceModel.type = newOperation.interfaceType; + uiInterfaceModel.uniqueId = newOperation.interfaceType; + uiInterfaceModel.operations = []; + uiInterfaceModel.operations.push(new UIOperationModel(new OperationModel(newOperation))); + this.interfaces.push(uiInterfaceModel); + } + }, () => { + this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false; + this.modalServiceNg2.closeCurrentModal(); + }, () => { + this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false; + this.modalServiceNg2.closeCurrentModal(); + }); + } } private handleEnableAddArtifactImplementation = (newOperation: InterfaceOperationModel): InterfaceOperationModel => { diff --git a/catalog-ui/src/app/ng2/services/component-services/topology-template.service.ts b/catalog-ui/src/app/ng2/services/component-services/topology-template.service.ts index 0af8c737de..405d2bb8af 100644 --- a/catalog-ui/src/app/ng2/services/component-services/topology-template.service.ts +++ b/catalog-ui/src/app/ng2/services/component-services/topology-template.service.ts @@ -36,6 +36,7 @@ import { IFileDownload, InputBEModel, InstancePropertiesAPIMap, + InterfaceModel, OperationModel, PropertyModel, Requirement @@ -672,4 +673,29 @@ export class TopologyTemplateService { .pipe(map(response => response && response.defaultCustomToscaFunction ? response.defaultCustomToscaFunction : [])); } + createComponentInstanceInterfaceOperation(componentMetaDataId: string, componentInstanceId: string, + operation: InterfaceOperationModel): Observable<InterfaceOperationModel> { + const operationList = { + interfaces: { + [operation.interfaceType]: { + type: operation.interfaceType, + operations: { + [operation.name]: new BEInterfaceOperationModel(operation) + } + } + } + }; + return this.http.post<any>(this.baseUrl + 'services/' + componentMetaDataId + '/componentInstance/' + componentInstanceId + '/interfaceOperation', operationList) + .map((res: any) => { + const interf: InterfaceModel = _.find(res.interfaces, interf => interf.type === operation.interfaceType); + const newOperation: OperationModel = _.find(interf.operations, op => op.name === operation.name); + + return new InterfaceOperationModel({ + ...newOperation, + interfaceType: interf.type, + interfaceId: interf.uniqueId, + }); + }); + } + } |