From 032525a375681fb18cc498d8daed9d73faa21ec3 Mon Sep 17 00:00:00 2001 From: MichaelMorris Date: Tue, 23 Jun 2020 09:15:48 +0100 Subject: [PATCH] Support for Nested/Hierarchical Services Change-Id: I478cf2e1f9cf96443a3e35bf22ac2c9d72bca8f1 Issue-ID: SDC-3145 Signed-off-by: MichaelMorris --- .../components/impl/CategoriesImportManager.java | 5 + .../impl/ComponentInstanceBusinessLogic.java | 149 +++++++++++++++------ .../openecomp/sdc/be/tosca/ToscaExportHandler.java | 38 ++++-- .../impl/CategoriesImportManagerTest.java | 20 ++- .../impl/ComponentInstanceBusinessLogicTest.java | 78 ++++++++++- .../sdc/be/tosca/ToscaExportHandlerTest.java | 32 +++++ .../src/test/resources/types/categoryTypes.yml | 8 ++ .../be/dao/neo4j/GraphPropertiesDictionary.java | 1 + .../be/resources/data/category/CategoryData.java | 6 +- .../operations/NodeTemplateOperation.java | 4 +- .../operations/TopologyTemplateOperation.java | 2 + .../operations/ToscaElementOperation.java | 1 + .../operations/ToscaOperationFacade.java | 12 +- .../operations/ToscaOperationFacadeTest.java | 42 +++++- catalog-ui/cypress/fixtures/common/setup-ui.json | 1 + catalog-ui/src/app/models.ts | 2 + catalog-ui/src/app/models/category.ts | 1 + .../src/app/models/components/displayComponent.ts | 2 +- .../componentsInstances/componentInstance.ts | 6 +- .../componentsInstances/fullComponentInstance.ts | 2 +- .../serviceSubstitutionInstance.ts | 30 +++++ .../composition-ci-node-service-substitution.ts | 59 ++++++++ .../src/app/models/graph/nodes/nodes-factory.ts | 12 +- .../sdc-element-icon/sdc-element-icon.component.ts | 1 + .../graph/composition-graph.component.ts | 2 +- .../graph/utils/composition-graph-palette-utils.ts | 3 +- .../palette/services/palette.service.ts | 38 +++++- .../composition-panel.component.spec.ts.snap | 1 + .../panel/composition-panel.component.ts | 16 ++- .../panel-tabs/info-tab/info-tab.component.ts | 2 +- .../properties-assignment.page.component.ts | 3 +- .../topology-template.service.ts | 1 + catalog-ui/src/app/utils/component-factory.ts | 1 + .../src/app/utils/component-instance-factory.ts | 16 ++- catalog-ui/src/app/utils/constants.ts | 1 + .../datatypes/category/CategoryDataDefinition.java | 106 ++------------- .../sdc/be/datatypes/enums/GraphPropertyEnum.java | 2 +- .../sdc/be/datatypes/enums/OriginTypeEnum.java | 3 +- .../category/CategoryDataDefinitionTest.java | 129 ------------------ openecomp-ui/yarn.lock | 21 +++ 40 files changed, 551 insertions(+), 308 deletions(-) create mode 100644 catalog-ui/src/app/models/componentsInstances/serviceSubstitutionInstance.ts create mode 100644 catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-service-substitution.ts diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CategoriesImportManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CategoriesImportManager.java index 0eeb1a7086..4330c0de43 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CategoriesImportManager.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CategoriesImportManager.java @@ -22,6 +22,7 @@ package org.openecomp.sdc.be.components.impl; import fj.data.Either; import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary; import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum; import org.openecomp.sdc.be.datamodel.utils.NodeTypeConvertUtils; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; @@ -237,6 +238,10 @@ public class CategoriesImportManager { catDef.setIcons(icons); String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(catName); catDef.setNormalizedName(normalizedName); + final Object useServiceSubstitutionForNestedServicesProperty = category.get("useServiceSubstitutionForNestedServices"); + final boolean useServiceSubstitutionForNestedServices = useServiceSubstitutionForNestedServicesProperty == null ? + false : (Boolean) useServiceSubstitutionForNestedServicesProperty; + catDef.setUseServiceSubstitutionForNestedServices(useServiceSubstitutionForNestedServices); categroiesDef.add(catDef); } 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 e616ff87d3..ce1eed1a4c 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,30 +349,56 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { final OriginTypeEnum originType = resourceInstance.getOriginType(); validateInstanceName(resourceInstance); if (originType == OriginTypeEnum.ServiceProxy) { - - final Either serviceProxyOrigin = - toscaOperationFacade.getLatestByName("serviceProxy"); - if (isServiceProxyOrigin(serviceProxyOrigin)) { - throw new ByActionStatusComponentException( - componentsUtils.convertFromStorageResponse(serviceProxyOrigin.right().value())); - } - origComponent = serviceProxyOrigin.left().value(); - - final StorageOperationStatus fillProxyRes = fillProxyInstanceData(resourceInstance, origComponent); - if (isFillProxyRes(fillProxyRes)) { - throw new ByActionStatusComponentException( - componentsUtils.convertFromStorageResponse(fillProxyRes)); + origComponent = getOrigComponentForServiceProxy(containerComponent, resourceInstance); + } else if (originType == OriginTypeEnum.ServiceSubstitution){ + origComponent = getOrigComponentForServiceSubstitution(resourceInstance); + } else { + origComponent = getAndValidateOriginComponentOfComponentInstance(containerComponent, resourceInstance); + validateOriginAndResourceInstanceTypes(containerComponent, origComponent, originType); } - } else { - origComponent = getAndValidateOriginComponentOfComponentInstance(containerComponent, - resourceInstance); + validateResourceInstanceState(containerComponent, origComponent); + overrideFields(origComponent, resourceInstance); + compositionBusinessLogic.validateAndSetDefaultCoordinates(resourceInstance); } - validateOriginAndResourceInstanceTypes(containerComponent, origComponent, originType); - validateResourceInstanceState(containerComponent, origComponent); - overrideFields(origComponent, resourceInstance); - compositionBusinessLogic.validateAndSetDefaultCoordinates(resourceInstance); + return createComponent(needLock, containerComponent,origComponent, resourceInstance, user); + + } + + private Component getOrigComponentForServiceProxy(org.openecomp.sdc.be.model.Component containerComponent, ComponentInstance resourceInstance) { + Either serviceProxyOrigin = toscaOperationFacade.getLatestByName("serviceProxy"); + if (isServiceProxyOrigin(serviceProxyOrigin)) { + throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(serviceProxyOrigin.right().value())); + } + Component origComponent = serviceProxyOrigin.left().value(); + + StorageOperationStatus fillProxyRes = fillInstanceData(resourceInstance, origComponent); + if (isFillProxyRes(fillProxyRes)) { + throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(fillProxyRes)); + } + validateOriginAndResourceInstanceTypes(containerComponent, origComponent, OriginTypeEnum.ServiceProxy); + return origComponent; + } + + private Component getOrigComponentForServiceSubstitution(ComponentInstance resourceInstance) { + final Either getServiceResult = toscaOperationFacade.getToscaFullElement(resourceInstance.getComponentUid()); + if (getServiceResult.isRight()) { + throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(getServiceResult.right().value())); + } + final Component service = getServiceResult.left().value(); + + final Either getServiceDerivedFromTypeResult = toscaOperationFacade.getLatestByToscaResourceName(service.getDerivedFromGenericType()); + if (getServiceDerivedFromTypeResult.isRight()) { + throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(getServiceResult.right().value())); + } + + Component origComponent = getServiceDerivedFromTypeResult.left().value(); + + final StorageOperationStatus fillProxyRes = fillInstanceData(resourceInstance, origComponent); + if (isFillProxyRes(fillProxyRes)) { + throw new ByActionStatusComponentException( + componentsUtils.convertFromStorageResponse(fillProxyRes)); } - return createComponent(needLock, containerComponent, origComponent, resourceInstance, user); + return origComponent; } private ComponentInstance createComponent(boolean needLock, Component containerComponent, Component origComponent, ComponentInstance resourceInstance, User user) { @@ -492,9 +518,8 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { return false; } - private StorageOperationStatus fillProxyInstanceData(ComponentInstance resourceInstance, Component proxyTemplate) { - resourceInstance.setIsProxy(true); - ComponentParametersView filter = new ComponentParametersView(true); + private StorageOperationStatus fillInstanceData(ComponentInstance resourceInstance, Component origComponent) { + final ComponentParametersView filter = new ComponentParametersView(true); filter.setIgnoreCapabilities(false); filter.setIgnoreCapabiltyProperties(false); filter.setIgnoreComponentInstances(false); @@ -507,38 +532,55 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { if (serviceRes.isRight()) { return serviceRes.right().value(); } - Component service = serviceRes.left().value(); - Map> capabilities = service.getCapabilities(); + final Component service = serviceRes.left().value(); + final Map> capabilities = service.getCapabilities(); resourceInstance.setCapabilities(capabilities); - Map> req = service.getRequirements(); + final Map> req = service.getRequirements(); resourceInstance.setRequirements(req); - Map serviceInterfaces = service.getInterfaces(); + final Map serviceInterfaces = service.getInterfaces(); if(MapUtils.isNotEmpty(serviceInterfaces)) { serviceInterfaces.forEach(resourceInstance::addInterface); } - - resourceInstance.setProperties(PropertiesUtils.getProperties(service)); - List serviceInputs = service.getInputs(); + final List serviceInputs = service.getInputs(); resourceInstance.setInputs(serviceInputs); - - String name = ValidationUtils.normalizeComponentInstanceName(service.getName()) + ToscaOperationFacade.PROXY_SUFFIX; - String toscaResourceName = ((Resource) proxyTemplate).getToscaResourceName(); - int lastIndexOf = toscaResourceName.lastIndexOf('.'); + resourceInstance.setSourceModelInvariant(service.getInvariantUUID()); + resourceInstance.setSourceModelName(service.getName()); + resourceInstance.setSourceModelUuid(service.getUUID()); + resourceInstance.setSourceModelUid(service.getUniqueId()); + resourceInstance.setComponentUid(origComponent.getUniqueId()); + resourceInstance.setComponentVersion(service.getVersion()); + + switch(resourceInstance.getOriginType()) { + case ServiceProxy: + return fillProxyInstanceData(resourceInstance, origComponent, service); + case ServiceSubstitution: + return fillServiceSubstitutableNodeTypeData(resourceInstance, service); + default: + return StorageOperationStatus.OK; + } + } + + private StorageOperationStatus fillProxyInstanceData(final ComponentInstance resourceInstance, final Component origComponent, final Component service) { + final String name = ValidationUtils.normalizeComponentInstanceName(service.getName()) + ToscaOperationFacade.PROXY_SUFFIX; + final String toscaResourceName = ((Resource) origComponent).getToscaResourceName(); + final int lastIndexOf = toscaResourceName.lastIndexOf('.'); if (lastIndexOf != -1) { - String proxyToscaName = toscaResourceName.substring(0, lastIndexOf + 1) + name; + final String proxyToscaName = toscaResourceName.substring(0, lastIndexOf + 1) + name; resourceInstance.setToscaComponentName(proxyToscaName); } resourceInstance.setName(name); resourceInstance.setIsProxy(true); - resourceInstance.setSourceModelInvariant(service.getInvariantUUID()); - resourceInstance.setSourceModelName(service.getName()); - resourceInstance.setSourceModelUuid(service.getUUID()); - resourceInstance.setSourceModelUid(service.getUniqueId()); - resourceInstance.setComponentUid(proxyTemplate.getUniqueId()); resourceInstance.setDescription("A Proxy for Service " + service.getName()); - resourceInstance.setComponentVersion(service.getVersion()); + return StorageOperationStatus.OK; + } + + private StorageOperationStatus fillServiceSubstitutableNodeTypeData(final ComponentInstance resourceInstance, final Component service) { + resourceInstance.setToscaComponentName("org.openecomp.service." + ValidationUtils.convertToSystemName(service.getName())); + resourceInstance.setName(ValidationUtils.normalizeComponentInstanceName(service.getName())); + resourceInstance.setIsProxy(false); + resourceInstance.setDescription("A substitutable node type for service " + service.getName()); return StorageOperationStatus.OK; } @@ -2348,6 +2390,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { Component origComponent = null; OriginTypeEnum originType = currentResourceInstance.getOriginType(); if (originType == OriginTypeEnum.ServiceProxy) { + newComponentInstance.setOriginType(originType); Either serviceProxyOrigin = toscaOperationFacade .getLatestByName("serviceProxy"); if (isServiceProxyOrigin(serviceProxyOrigin)) { @@ -2356,13 +2399,33 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { } origComponent = serviceProxyOrigin.left().value(); - StorageOperationStatus fillProxyRes = fillProxyInstanceData(newComponentInstance, origComponent); + StorageOperationStatus fillProxyRes = fillInstanceData(newComponentInstance, origComponent); if (isFillProxyRes(fillProxyRes)) { throw new ByActionStatusComponentException( componentsUtils.convertFromStorageResponse(fillProxyRes)); } + } else if (originType == OriginTypeEnum.ServiceSubstitution){ newComponentInstance.setOriginType(originType); + + final Either getServiceResult = toscaOperationFacade.getToscaFullElement(newComponentInstance.getComponentUid()); + if (getServiceResult.isRight()) { + throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(getServiceResult.right().value())); + } + final Component service = getServiceResult.left().value(); + + final Either getServiceDerivedFromTypeResult = toscaOperationFacade.getLatestByToscaResourceName(service.getDerivedFromGenericType()); + if (getServiceDerivedFromTypeResult.isRight()) { + throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(getServiceResult.right().value())); + } + + origComponent = getServiceDerivedFromTypeResult.left().value(); + + final StorageOperationStatus fillProxyRes = fillInstanceData(newComponentInstance, origComponent); + if (isFillProxyRes(fillProxyRes)) { + throw new ByActionStatusComponentException( + componentsUtils.convertFromStorageResponse(fillProxyRes)); + } } else { origComponent = getOriginComponentFromComponentInstance(newComponentInstance); newComponentInstance.setName(resResourceInfo.getName()); 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 518ed5726c..45db4f7365 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 @@ -25,10 +25,6 @@ import static org.apache.commons.collections.CollectionUtils.isNotEmpty; import static org.apache.commons.collections.MapUtils.isNotEmpty; import static org.openecomp.sdc.be.components.utils.PropertiesUtils.resolvePropertyValueFromInput; import static org.openecomp.sdc.be.tosca.InterfacesOperationsConverter.addInterfaceTypeElement; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import fj.data.Either; import java.beans.IntrospectionException; import java.util.ArrayList; import java.util.Collection; @@ -125,6 +121,9 @@ import org.yaml.snakeyaml.nodes.NodeTuple; import org.yaml.snakeyaml.nodes.Tag; import org.yaml.snakeyaml.representer.Represent; import org.yaml.snakeyaml.representer.Representer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import fj.data.Either; @org.springframework.stereotype.Component("tosca-export-handler") public class ToscaExportHandler { @@ -282,6 +281,8 @@ public class ToscaExportHandler { if (nodeTypesMap != null && !nodeTypesMap.isEmpty()) { toscaNode.setNode_types(nodeTypesMap); } + + createServiceSubstitutionNodeTypes(componentCache, component, toscaNode); Either, ToscaError> proxyInterfaceTypesEither = createProxyInterfaceTypes(component); if (proxyInterfaceTypesEither.isRight()) { @@ -428,8 +429,11 @@ public class ToscaExportHandler { toscaMetadata.setSourceModelInvariant(componentInstance.getSourceModelInvariant()); toscaMetadata.setSourceModelUuid(componentInstance.getSourceModelUuid()); toscaMetadata.setSourceModelName(componentInstance.getSourceModelName()); - toscaMetadata.setName( - componentInstance.getSourceModelName() + " " + OriginTypeEnum.ServiceProxy.getDisplayValue()); + if (componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy) { + toscaMetadata.setName(componentInstance.getSourceModelName() + " " + OriginTypeEnum.ServiceProxy.getDisplayValue()); + } else if (componentInstance.getOriginType() == OriginTypeEnum.ServiceSubstitution) { + toscaMetadata.setName(componentInstance.getSourceModelName() + " " + OriginTypeEnum.ServiceSubstitution.getDisplayValue()); + } toscaMetadata.setDescription(componentInstance.getDescription()); } @@ -438,7 +442,7 @@ public class ToscaExportHandler { case RESOURCE: Resource resource = (Resource) component; - if (isInstance && componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy) { + if (isInstance && (componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy || componentInstance.getOriginType() == OriginTypeEnum.ServiceSubstitution)) { toscaMetadata.setType(componentInstance.getOriginType().getDisplayValue()); } else { toscaMetadata.setType(resource.getResourceType().name()); @@ -546,7 +550,7 @@ public class ToscaExportHandler { final ComponentInstance componentInstance, final Component fetchedComponent) { componentCache.put(fetchedComponent.getUniqueId(), fetchedComponent); - if (componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy) { + if (componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy || componentInstance.getOriginType() == OriginTypeEnum.ServiceSubstitution) { final Either sourceService = toscaOperationFacade .getToscaFullElement(componentInstance.getSourceModelUid()); if (sourceService.isRight() && (log.isDebugEnabled())) { @@ -1181,6 +1185,24 @@ public class ToscaExportHandler { return Either.left(nodeTypesMap); } + + private void createServiceSubstitutionNodeTypes(final Map componentCache, + final Component container, final ToscaTemplate toscaNode) { + final List componentInstances = container.getComponentInstances(); + + if (CollectionUtils.isEmpty(componentInstances)) { + return; + } + final List serviceSubstitutionInstanceList = componentInstances.stream() + .filter(p -> p.getOriginType().name().equals(OriginTypeEnum.ServiceSubstitution.name())) + .collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(serviceSubstitutionInstanceList)) { + for (ComponentInstance inst : serviceSubstitutionInstanceList) { + final Map nodeTypes = toscaNode.getNode_types() == null ? new HashMap<>() : toscaNode.getNode_types(); + convertInterfaceNodeType(new HashMap<>(), componentCache.get(inst.getSourceModelUid()), toscaNode, nodeTypes, true); + } + } + } private ToscaNodeType createProxyNodeType(Map componentCache, Component origComponent, Component proxyComponent, ComponentInstance instance) { diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/CategoriesImportManagerTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/CategoriesImportManagerTest.java index 4be50e81ae..1d96272716 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/CategoriesImportManagerTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/CategoriesImportManagerTest.java @@ -43,7 +43,10 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import java.util.Map; - +import java.util.Optional; +import java.util.stream.Stream; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.when; @@ -86,8 +89,21 @@ public class CategoriesImportManagerTest { public void importCategoriesTest() throws IOException { String ymlContent = getYmlContent(); Either>, ResponseFormat> createCapabilityTypes = importManager.createCategories(ymlContent); - assertTrue(createCapabilityTypes.isLeft()); + + assertTrue(createCapabilityTypes.isLeft()); + final Map> categories = createCapabilityTypes.left().value(); + final Optional categoryVoIPCallControl = categories.get("services").stream().filter(category -> category.getName().equals("VoIP Call Control")).findAny(); + final Optional categoryWithServiceSubstitutionTrue = categories.get("services").stream().filter(category -> category.getName().equals("Category With Service Substitution True")).findAny(); + final Optional categoryWithServiceSubstitutionFalse = categories.get("services").stream().filter(category -> category.getName().equals("Category With Service Substitution False")).findAny(); + + + assertTrue(categoryVoIPCallControl.isPresent()); + assertFalse(categoryVoIPCallControl.get().isUseServiceSubstitutionForNestedServices()); + assertTrue(categoryWithServiceSubstitutionTrue.isPresent()); + assertTrue(categoryWithServiceSubstitutionTrue.get().isUseServiceSubstitutionForNestedServices()); + assertTrue(categoryWithServiceSubstitutionFalse.isPresent()); + assertFalse(categoryWithServiceSubstitutionFalse.get().isUseServiceSubstitutionForNestedServices()); } private String getYmlContent() throws IOException { diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogicTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogicTest.java index f213835406..d585c6f77a 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogicTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogicTest.java @@ -1556,7 +1556,7 @@ class ComponentInstanceBusinessLogicTest { componentInst.setDeploymentArtifacts(component.getDeploymentArtifacts()); return componentInst; } - + // Prepare ComponentInstance & Resource objects used in createComponentInstance() tests private Pair prepareResourcesForCreateComponentInstanceTest() { ComponentInstance instanceToBeCreated = new ComponentInstance(); @@ -1802,4 +1802,80 @@ class ComponentInstanceBusinessLogicTest { // Check graph db change was committed verify(janusGraphDao, times(1)).commit(); } + + @Test + void testCreateComponentInstanceServiceSubstitutionSuccess() { + ComponentInstance instanceToBeCreated = createServiceSubstitutionComponentInstance(); + Service originService = createServiceSubstitutionOriginService(); + Component serviceBaseComponent = createServiceSubstitutionServiceDerivedFromComponent(); + + Service updatedService = new Service(); + updatedService.setComponentInstances(Collections.singletonList(instanceToBeCreated)); + updatedService.setUniqueId(service.getUniqueId()); + + when(toscaOperationFacade.getToscaElement(eq(COMPONENT_ID), any(ComponentParametersView.class))) + .thenReturn(Either.left(service)); + when(toscaOperationFacade.getToscaFullElement(eq(ORIGIN_COMPONENT_ID))) + .thenReturn(Either.left(originService)); + when(toscaOperationFacade.getLatestByToscaResourceName(eq(originService.getDerivedFromGenericType()))) + .thenReturn(Either.left(serviceBaseComponent)); + when(toscaOperationFacade.getToscaElement(eq(ORIGIN_COMPONENT_ID), any(ComponentParametersView.class))) + .thenReturn(Either.left(originService)); + Mockito.doNothing().when(compositionBusinessLogic).validateAndSetDefaultCoordinates(instanceToBeCreated); + when(graphLockOperation.lockComponent(COMPONENT_ID, NodeTypeEnum.Service)) + .thenReturn(StorageOperationStatus.OK); + when(toscaOperationFacade.addComponentInstanceToTopologyTemplate(service, serviceBaseComponent, instanceToBeCreated, false, user)) + .thenReturn(Either.left(new ImmutablePair<>(updatedService, COMPONENT_INSTANCE_ID))); + when(artifactsBusinessLogic.getArtifacts( + "baseComponentId", NodeTypeEnum.Resource, ArtifactGroupTypeEnum.DEPLOYMENT, null)) + .thenReturn(Either.left(new HashMap<>())); + when(toscaOperationFacade + .addInformationalArtifactsToInstance(service.getUniqueId(), instanceToBeCreated, originService.getArtifacts())) + .thenReturn(StorageOperationStatus.OK); + when(janusGraphDao.commit()).thenReturn(JanusGraphOperationStatus.OK); + when(graphLockOperation.unlockComponent(COMPONENT_ID, NodeTypeEnum.Service)) + .thenReturn(StorageOperationStatus.OK); + + ComponentInstance result = componentInstanceBusinessLogic.createComponentInstance( + ComponentTypeEnum.SERVICE_PARAM_NAME, COMPONENT_ID, USER_ID, instanceToBeCreated); + assertThat(result).isEqualTo(instanceToBeCreated); + assertThat(instanceToBeCreated.getComponentVersion()).isEqualTo(originService.getVersion()); + assertThat(instanceToBeCreated.getIcon()).isEqualTo(originService.getIcon()); + verify(compositionBusinessLogic, times(1)).validateAndSetDefaultCoordinates(instanceToBeCreated); + verify(toscaOperationFacade, times(1)) + .addComponentInstanceToTopologyTemplate(service, serviceBaseComponent, instanceToBeCreated, false, user); + // Check graph db change was committed + verify(janusGraphDao, times(1)).commit(); + } + + private ComponentInstance createServiceSubstitutionComponentInstance() { + final ComponentInstance instanceToBeCreated = new ComponentInstance(); + instanceToBeCreated.setName(COMPONENT_INSTANCE_NAME); + instanceToBeCreated.setUniqueId(COMPONENT_INSTANCE_ID); + instanceToBeCreated.setComponentUid(ORIGIN_COMPONENT_ID); + instanceToBeCreated.setOriginType(OriginTypeEnum.ServiceSubstitution); + + return instanceToBeCreated; + } + + private Service createServiceSubstitutionOriginService() { + final Service originComponent = new Service(); + originComponent.setLifecycleState(LifecycleStateEnum.CERTIFIED); + originComponent.setVersion(ORIGIN_COMPONENT_VERSION); + originComponent.setIcon(ICON_NAME); + originComponent.setDerivedFromGenericType("org.openecomp.resource.abstract.nodes.service"); + originComponent.setName("myService"); + return originComponent; + } + + + private Component createServiceSubstitutionServiceDerivedFromComponent() { + final Resource component = new Resource(); + component.setLifecycleState(LifecycleStateEnum.CERTIFIED); + component.setVersion(ORIGIN_COMPONENT_VERSION); + component.setIcon(ICON_NAME); + component.setToscaResourceName("org.openecomp.resource.abstract.nodes.service"); + component.setUniqueId("baseComponentId"); + return component; + } } diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java index 45cdbbdfaa..d54fc98c9a 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java @@ -997,6 +997,38 @@ public class ToscaExportHandlerTest extends BeConfDependentTest { result = Deencapsulation.invoke(testSubject, "createProxyNodeTypes", componentCache, container); Assert.assertNotNull(result); } + + @Test + public void testCreateServiceSubstitutionNodeTypes() throws Exception { + Map componentCache = new HashMap<>(); + + Component referencedService = getNewService(); + referencedService.setInvariantUUID("uuid"); + referencedService.setUUID("uuid"); + referencedService.setUniqueId("targetModelUid"); + referencedService.setDescription("desc"); + componentCache.put("targetModelUid", referencedService); + + Component containerService = new Service(); + List componentInstances = new ArrayList<>(); + ComponentInstance instance = new ComponentInstance(); + instance.setOriginType(OriginTypeEnum.ServiceSubstitution); + instance.setSourceModelUid("targetModelUid"); + + componentInstances.add(instance); + containerService.setComponentInstances(componentInstances); + + Mockito.when(interfaceLifecycleOperation.getAllInterfaceLifecycleTypes()) + .thenReturn(Either.left(Collections.emptyMap())); + Mockito.when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>())); + Mockito.when(capabiltyRequirementConvertor.convertRequirements(any(Map.class), any(Service.class), + any(ToscaNodeType.class))).thenReturn(Either.left(new ToscaNodeType())); + + ToscaTemplate toscaNode = new ToscaTemplate("1_1"); + + Deencapsulation.invoke(testSubject, "createServiceSubstitutionNodeTypes", componentCache, containerService, toscaNode); + Assert.assertNotNull(toscaNode.getNode_types()); + } @Test public void testCreateProxyNodeTypesWhenGetLatestByNameReturnValue() { diff --git a/catalog-be/src/test/resources/types/categoryTypes.yml b/catalog-be/src/test/resources/types/categoryTypes.yml index c853f9a52c..36268b1fff 100644 --- a/catalog-be/src/test/resources/types/categoryTypes.yml +++ b/catalog-be/src/test/resources/types/categoryTypes.yml @@ -11,6 +11,14 @@ services: VoIP_Call_Control: name: "VoIP Call Control" icons: ['call_controll'] + Category_With_ServiceSubstitution_True: + name: "Category With Service Substitution True" + icons: ['network_l_4'] + useServiceSubstitutionForNestedServices: true + Category_With_ServiceSubstitution_False: + name: "Category With Service Substitution False" + icons: ['network_l_4'] + useServiceSubstitutionForNestedServices: false resources: NetworkLayer23: name: "Network Layer 2-3" diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java index f0806291c7..e27839ecb9 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java @@ -122,6 +122,7 @@ public enum GraphPropertiesDictionary { CONTACTS ("contacts", String.class, false, false), //categorys ICONS ("icons", String.class, false, false), + USE_SERVICE_SUBSTITUTION_FOR_NESTED_SERVICES ("useServiceSubstitutionForNestedServices", Boolean.class, false, false), //relation CAPABILITY_OWNER_ID ("capOwnerId", String.class, false, false), REQUIREMENT_OWNER_ID ("reqOwnerId", String.class, false, false), diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/category/CategoryData.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/category/CategoryData.java index f5e76ae8aa..8db7b53017 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/category/CategoryData.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/category/CategoryData.java @@ -51,6 +51,9 @@ public class CategoryData extends GraphNode { categoryDataDefinition .setNormalizedName((String) properties.get(GraphPropertiesDictionary.NORMALIZED_NAME.getProperty())); categoryDataDefinition.setName((String) properties.get(GraphPropertiesDictionary.NAME.getProperty())); + final Object useServiceSubstitutionForNestedServicesProperty = properties.get(GraphPropertiesDictionary.USE_SERVICE_SUBSTITUTION_FOR_NESTED_SERVICES.getProperty()); + final boolean useServiceSubstitutionForNestedServices = useServiceSubstitutionForNestedServicesProperty != null && (boolean) useServiceSubstitutionForNestedServicesProperty; + categoryDataDefinition.setUseServiceSubstitutionForNestedServices(useServiceSubstitutionForNestedServices); Type listType = new TypeToken>() { }.getType(); @@ -77,7 +80,8 @@ public class CategoryData extends GraphNode { addIfExists(map, GraphPropertiesDictionary.NORMALIZED_NAME, categoryDataDefinition.getNormalizedName()); // String icons=getGson().toJson(categoryDataDefinition.getIcons()); // addIfExists(map, GraphPropertiesDictionary.ICONS, icons); - addIfExists(map, GraphPropertiesDictionary.ICONS, categoryDataDefinition.getIcons()); + addIfExists(map, GraphPropertiesDictionary.ICONS, categoryDataDefinition.getIcons()); + addIfExists(map, GraphPropertiesDictionary.USE_SERVICE_SUBSTITUTION_FOR_NESTED_SERVICES, categoryDataDefinition.isUseServiceSubstitutionForNestedServices()); return map; } 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 9cadd4e107..df1f8fd8bf 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 @@ -165,7 +165,7 @@ public class NodeTemplateOperation extends BaseOperation { } result = Either.right(status); } - if (componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy) { + if (componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy || componentInstance.getOriginType() == OriginTypeEnum.ServiceSubstitution) { TopologyTemplate updatedContainer = addComponentInstanceRes.left().value(); result = addCapAndReqToProxyServiceInstance(updatedContainer, componentInstance, componentInstanceData); if(result.isRight()) { @@ -292,7 +292,7 @@ public class NodeTemplateOperation extends BaseOperation { Either result = null; String instanceName = componentInstance.getName(); - if (StringUtils.isEmpty(instanceName) || instanceName.equalsIgnoreCase(originToscaElement.getName()) || componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy) { + if (StringUtils.isEmpty(instanceName) || instanceName.equalsIgnoreCase(originToscaElement.getName()) || componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy || componentInstance.getOriginType() == OriginTypeEnum.ServiceSubstitution) { instanceName = buildComponentInstanceName(instanceNumberSuffix, instanceName); } else if (!isUniqueInstanceName(container, componentInstance.getName())) { CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to create component instance with name {} on component container {}. The instance with the same name already exists. ", componentInstance.getName(), container.getName()); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/TopologyTemplateOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/TopologyTemplateOperation.java index af6ddd82e5..3109107f03 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/TopologyTemplateOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/TopologyTemplateOperation.java @@ -1183,6 +1183,8 @@ public class TopologyTemplateOperation extends ToscaElementOperation { category.setUniqueId(categoryV.getUniqueId()); category.setNormalizedName((String) metadataProperties.get(GraphPropertyEnum.NORMALIZED_NAME)); category.setName((String) metadataProperties.get(GraphPropertyEnum.NAME)); + final Boolean useServiceSubstitutionForNestedServices = (Boolean)metadataProperties.get(GraphPropertyEnum.USE_SUBSTITUTION_FOR_NESTED_SERVICES); + category.setUseServiceSubstitutionForNestedServices(useServiceSubstitutionForNestedServices == null ? false : useServiceSubstitutionForNestedServices); Type listTypeCat = new TypeToken>() {}.getType(); List iconsfromJsonCat = getGson().fromJson((String) metadataProperties.get(GraphPropertyEnum.ICONS.getProperty()), listTypeCat); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementOperation.java index 90111e80ac..ba488fe2af 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementOperation.java @@ -1005,6 +1005,7 @@ public abstract class ToscaElementOperation extends BaseOperation { category.setUniqueId((String) categoryV.property(GraphPropertyEnum.UNIQUE_ID.getProperty()).value()); category.setNormalizedName(categoryNormalizedName); category.setName((String) categoryV.property(GraphPropertyEnum.NAME.getProperty()).value()); + category.setUseServiceSubstitutionForNestedServices((Boolean) categoryV.property(GraphPropertyEnum.USE_SUBSTITUTION_FOR_NESTED_SERVICES.getProperty()).orElse(false)); categories.add(category); catalogComponent.setCategories(categories); 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 5b4388226b..aa03d761bf 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 @@ -808,7 +808,17 @@ public class ToscaOperationFacade { if (StringUtils.isEmpty(componentInstance.getIcon())) { componentInstance.setIcon(origComponent.getIcon()); } - String nameToFindForCounter = componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy ? ValidationUtils.normaliseComponentName(componentInstance.getSourceModelName()) + PROXY_SUFFIX : origComponent.getName(); + String nameToFindForCounter; + switch (componentInstance.getOriginType()) { + case ServiceProxy: + nameToFindForCounter = ValidationUtils.normaliseComponentName(componentInstance.getSourceModelName()) + PROXY_SUFFIX; + break; + case ServiceSubstitution: + nameToFindForCounter = ValidationUtils.normaliseComponentName(componentInstance.getSourceModelName()); + break; + default: + nameToFindForCounter = origComponent.getName(); + } String nextComponentInstanceCounter = getNextComponentInstanceCounter(containerComponent, nameToFindForCounter); Either, StorageOperationStatus> addResult = nodeTemplateOperation.addComponentInstanceToTopologyTemplate(ModelConverter.convertToToscaElement(containerComponent), ModelConverter.convertToToscaElement(origComponent), nextComponentInstanceCounter, componentInstance, allowDeleted, user); diff --git a/catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacadeTest.java b/catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacadeTest.java index caf1805b83..1c730e5718 100644 --- a/catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacadeTest.java +++ b/catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacadeTest.java @@ -106,6 +106,7 @@ public class ToscaOperationFacadeTest { private static final String ICON_NAME = "icon"; private static final String SERVICE_MODEL_NAME = "Test_Service"; private static final String SERVICE_PROXY_INSTANCE0_NAME = "testservice_proxy0"; + private static final String SERVICE_SUBSTITUTION_INSTANCE0_NAME = "testservice0"; @InjectMocks private ToscaOperationFacade testInstance; @@ -637,7 +638,7 @@ public class ToscaOperationFacadeTest { } @Test - public void testAddComponentInstanceToTopologyTemplate() { + public void testAddComponentInstanceToTopologyTemplate_ServiceProxy() { Component containerComponent = new Service(); Component originalComponent = new Service(); ComponentInstance componentInstance = new ComponentInstance(); @@ -677,6 +678,45 @@ public class ToscaOperationFacadeTest { verify(nodeTemplateOperationMock, times(1)) .addComponentInstanceToTopologyTemplate(any(), any(), eq("1"), eq(componentInstance), eq(false), eq(user)); } + @Test + public void testAddComponentInstanceToTopologyTemplate_ServiceSubstitution() { + Component containerComponent = new Service(); + Component originalComponent = new Service(); + ComponentInstance componentInstance = new ComponentInstance(); + ComponentInstance existingComponentInstance = new ComponentInstance(); + User user = new User(); + + containerComponent.setComponentType(ComponentTypeEnum.SERVICE); + + originalComponent.setComponentType(ComponentTypeEnum.SERVICE); + originalComponent.setIcon(ICON_NAME); + + componentInstance.setOriginType(OriginTypeEnum.ServiceSubstitution); + componentInstance.setSourceModelName(SERVICE_MODEL_NAME); + + List existingInstances = new ArrayList<>(); + existingComponentInstance.setNormalizedName(SERVICE_SUBSTITUTION_INSTANCE0_NAME); + existingInstances.add(existingComponentInstance); + containerComponent.setComponentInstances(existingInstances); + + when(nodeTemplateOperationMock + .addComponentInstanceToTopologyTemplate(any(), any(), eq("1"), eq(componentInstance), eq(false), eq(user))) + .thenReturn(Either.left(new ImmutablePair<>(new TopologyTemplate(), COMPONENT_ID))); + TopologyTemplate topologyTemplate = new TopologyTemplate(); + topologyTemplate.setMetadataValue(JsonPresentationFields.COMPONENT_TYPE, ComponentTypeEnum.SERVICE.name()); + when(topologyTemplateOperationMock.getToscaElement(containerComponent.getUniqueId())) + .thenReturn(Either.left(topologyTemplate)); + + Either, StorageOperationStatus> result = + testInstance.addComponentInstanceToTopologyTemplate( + containerComponent, originalComponent, componentInstance, false, user); + + assertTrue(result.isLeft()); + assertEquals(ICON_NAME, componentInstance.getIcon()); + assertEquals(COMPONENT_ID, result.left().value().getRight()); + verify(nodeTemplateOperationMock, times(1)) + .addComponentInstanceToTopologyTemplate(any(), any(), eq("1"), eq(componentInstance), eq(false), eq(user)); + } private Either associatePolicyToComponentWithStatus(StorageOperationStatus status) { PolicyDefinition policy = new PolicyDefinition(); diff --git a/catalog-ui/cypress/fixtures/common/setup-ui.json b/catalog-ui/cypress/fixtures/common/setup-ui.json index cdc8b0b58c..2c619a3eb2 100644 --- a/catalog-ui/cypress/fixtures/common/setup-ui.json +++ b/catalog-ui/cypress/fixtures/common/setup-ui.json @@ -5,6 +5,7 @@ "VFC": "VFC", "Configuration": "Configuration ()", "ServiceProxy": "ServiceProxy ()", + "ServiceSubstitution": "ServiceSubstitution ()", "VL": "VL", "VFCMT": "VFCMT", "PNF": "PNF", diff --git a/catalog-ui/src/app/models.ts b/catalog-ui/src/app/models.ts index 91fa4a7f33..ad201e2307 100644 --- a/catalog-ui/src/app/models.ts +++ b/catalog-ui/src/app/models.ts @@ -42,6 +42,7 @@ export * from './models/componentsInstances/componentInstance'; export * from './models/componentsInstances/resourceInstance'; export * from './models/componentsInstances/serviceInstance'; export * from './models/componentsInstances/serviceProxyInstance'; +export * from './models/componentsInstances/serviceSubstitutionInstance'; export * from './models/graph/zones/group-instance'; export * from './models/graph/zones/policy-instance'; export * from './models/graph/zones/zone'; @@ -83,6 +84,7 @@ export * from './models/graph/nodes/composition-graph-nodes/composition-ci-node- export * from './models/graph/nodes/composition-graph-nodes/composition-ci-node-configuration'; export * from './models/graph/nodes/composition-graph-nodes/composition-ci-node-service'; export * from './models/graph/nodes/composition-graph-nodes/composition-ci-node-service-proxy'; +export * from './models/graph/nodes/composition-graph-nodes/composition-ci-node-service-substitution'; export * from './models/graph/nodes/composition-graph-nodes/composition-ci-node-ucpe-cp'; export * from './models/graph/nodes/composition-graph-nodes/composition-ci-node-ucpe'; export * from './models/graph/nodes/composition-graph-nodes/composition-ci-node-vf'; diff --git a/catalog-ui/src/app/models/category.ts b/catalog-ui/src/app/models/category.ts index 0d5c63b5c1..15df98569d 100644 --- a/catalog-ui/src/app/models/category.ts +++ b/catalog-ui/src/app/models/category.ts @@ -37,6 +37,7 @@ export interface ICategoryBase { export interface IMainCategory extends ICategoryBase { subcategories:Array; + useServiceSubstitutionForNestedServices:boolean; } export interface ISubCategory extends ICategoryBase { diff --git a/catalog-ui/src/app/models/components/displayComponent.ts b/catalog-ui/src/app/models/components/displayComponent.ts index 4e946954f3..2e89bd0adf 100644 --- a/catalog-ui/src/app/models/components/displayComponent.ts +++ b/catalog-ui/src/app/models/components/displayComponent.ts @@ -28,6 +28,7 @@ import { PolicyMetadata } from '../policy-metadata'; import { GroupMetadata } from '../group-metadata'; import { RequirementsGroup } from '../requirement'; import { CapabilitiesGroup } from '../capability'; +import { IMainCategory } from '../category'; export enum LeftPaletteMetadataTypes { Component = 'COMPONENT', @@ -77,7 +78,6 @@ export class LeftPaletteComponent { } private initComponent(component: ComponentMetadata): void { - this.version = component.version; this.uniqueId = component.uniqueId; this.uuid = component.uuid; diff --git a/catalog-ui/src/app/models/componentsInstances/componentInstance.ts b/catalog-ui/src/app/models/componentsInstances/componentInstance.ts index e311589637..e91fcc9663 100644 --- a/catalog-ui/src/app/models/componentsInstances/componentInstance.ts +++ b/catalog-ui/src/app/models/componentsInstances/componentInstance.ts @@ -157,13 +157,17 @@ export class ComponentInstance implements IComponentInstance{ public isServiceProxy = ():boolean => { return this.originType === ComponentType.SERVICE_PROXY; } + + public isServiceSubstitution = ():boolean => { + return this.originType === ComponentType.SERVICE_SUBSTITUTION; + } public isVFC = ():boolean => { return this.originType === ResourceType.VFC; } public getComponentUid = ():string => { - return this.isServiceProxy()? this.sourceModelUid : this.componentUid; + return this.isServiceProxy() || this.isServiceSubstitution() ? this.sourceModelUid : this.componentUid; } public setInstanceRC = ():void=> { diff --git a/catalog-ui/src/app/models/componentsInstances/fullComponentInstance.ts b/catalog-ui/src/app/models/componentsInstances/fullComponentInstance.ts index ab9015d949..50a9eeb1d1 100644 --- a/catalog-ui/src/app/models/componentsInstances/fullComponentInstance.ts +++ b/catalog-ui/src/app/models/componentsInstances/fullComponentInstance.ts @@ -66,7 +66,7 @@ export class FullComponentInstance extends ComponentInstance { this.directives = componentInstance.directives; - if(originComponent.componentType === ComponentType.SERVICE || originComponent.componentType === ComponentType.SERVICE_PROXY){ + if(originComponent.componentType === ComponentType.SERVICE || originComponent.componentType === ComponentType.SERVICE_PROXY || ComponentType.SERVICE_SUBSTITUTION){ this.isServiceInstance = true; this.serviceApiArtifacts = (originComponent).serviceApiArtifacts; this.serviceType = (originComponent).serviceType; diff --git a/catalog-ui/src/app/models/componentsInstances/serviceSubstitutionInstance.ts b/catalog-ui/src/app/models/componentsInstances/serviceSubstitutionInstance.ts new file mode 100644 index 0000000000..6f91a62312 --- /dev/null +++ b/catalog-ui/src/app/models/componentsInstances/serviceSubstitutionInstance.ts @@ -0,0 +1,30 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Nordix Foundation + * ================================================================================ + * 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========================================================= + */ + +'use strict'; +import {ComponentInstance} from "./componentInstance"; + +export class ServiceSubstitutionInstance extends ComponentInstance { + + constructor(componentInstance?:ServiceSubstitutionInstance) { + super(componentInstance); + this.iconSprite = "sprite-services-icons"; + } +} + diff --git a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-service-substitution.ts b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-service-substitution.ts new file mode 100644 index 0000000000..94f85e316b --- /dev/null +++ b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-service-substitution.ts @@ -0,0 +1,59 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Nordix Foundation + * ================================================================================ + * 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========================================================= + */ + +import { ImagesUrl, GraphUIObjects} from "../../../../utils/constants"; +import {ComponentInstance, CompositionCiNodeBase} from "../../../../models"; +import {ImageCreatorService} from "app/ng2/pages/composition/graph/common/image-creator.service"; +export class CompositionCiNodeServiceSubstitution extends CompositionCiNodeBase { + private isDependent: boolean; + private originalImg: string; + + constructor(instance:ComponentInstance, + imageCreator:ImageCreatorService) { + super(instance, imageCreator); + this.isDependent =instance.isDependent(); + this.initService(); + } + + private initService():void { + this.imagesPath = this.imagesPath + ImagesUrl.SERVICE_PROXY_ICONS; + this.img = this.imagesPath + this.componentInstance.icon + '.png'; + this.originalImg = this.img; + this.imgWidth = GraphUIObjects.DEFAULT_RESOURCE_WIDTH; + this.classes = 'service-node'; + if(this.archived){ + this.classes = this.classes + ' archived'; + return; + } + if (this.isDependent) { + this.classes += ' dependent'; + } + if (!this.certified) { + this.classes = this.classes + ' not-certified'; + } + + } + public initUncertifiedDependentImage(node:Cy.Collection, nodeMinSize:number):string { + return this.enhanceImage(node, nodeMinSize, this.imagesPath + 'uncertified_dependent.png'); + } + + public initDependentImage(node:Cy.Collection, nodeMinSize:number):string { + return this.enhanceImage(node, nodeMinSize, this.imagesPath + 'dependent.png'); + } +} diff --git a/catalog-ui/src/app/models/graph/nodes/nodes-factory.ts b/catalog-ui/src/app/models/graph/nodes/nodes-factory.ts index fbcd479603..57b245e3a8 100644 --- a/catalog-ui/src/app/models/graph/nodes/nodes-factory.ts +++ b/catalog-ui/src/app/models/graph/nodes/nodes-factory.ts @@ -30,6 +30,7 @@ import { NodeUcpe, CompositionCiNodeService, CompositionCiNodeServiceProxy, + CompositionCiNodeServiceSubstitution, CompositionCiNodeBase, ComponentInstance, CompositionCiNodeVfc @@ -41,10 +42,10 @@ import {Injectable} from "@angular/core"; @Injectable() export class NodesFactory { - constructor(private imageCreator:ImageCreatorService) { + constructor(private imageCreator: ImageCreatorService) { } - public createNode = (instance:ComponentInstance):CompositionCiNodeBase => { + public createNode = (instance: ComponentInstance): CompositionCiNodeBase => { if (instance.isUcpe()) { return new NodeUcpe(instance, this.imageCreator); @@ -55,6 +56,9 @@ export class NodesFactory { if (instance.originType === ComponentType.SERVICE_PROXY) { return new CompositionCiNodeServiceProxy(instance, this.imageCreator); } + if (instance.originType === ComponentType.SERVICE_SUBSTITUTION) { + return new CompositionCiNodeServiceSubstitution(instance, this.imageCreator); + } if (instance.originType == ResourceType.VFC) { return new CompositionCiNodeVfc(instance, this.imageCreator); } @@ -71,11 +75,11 @@ export class NodesFactory { return new CompositionCiNodeVf(instance, this.imageCreator); }; - public createModuleNode = (module:Module):ModuleNodeBase => { + public createModuleNode = (module: Module): ModuleNodeBase => { return new ModuleNodeBase(module); }; - public createUcpeCpNode = (instance:ComponentInstance):CompositionCiNodeCp => { + public createUcpeCpNode = (instance: ComponentInstance): CompositionCiNodeCp => { return new CompositionCiNodeUcpeCp(instance, this.imageCreator); } diff --git a/catalog-ui/src/app/ng2/components/ui/sdc-element-icon/sdc-element-icon.component.ts b/catalog-ui/src/app/ng2/components/ui/sdc-element-icon/sdc-element-icon.component.ts index dd48af2f89..fc81a5bfdb 100644 --- a/catalog-ui/src/app/ng2/components/ui/sdc-element-icon/sdc-element-icon.component.ts +++ b/catalog-ui/src/app/ng2/components/ui/sdc-element-icon/sdc-element-icon.component.ts @@ -40,6 +40,7 @@ export class SdcElementIconComponent { this.elementIcon = new ElementIcon(this.iconName, "services_24", "lightBlue"); break; case ComponentType.SERVICE_PROXY: + case ComponentType.SERVICE_SUBSTITUTION: this.elementIcon = new ElementIcon(this.iconName, "services_24", "white", "primary"); break; case ResourceType.CONFIGURATION: diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.ts b/catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.ts index 5467ecedbc..45a7d4c576 100644 --- a/catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.ts +++ b/catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.ts @@ -622,7 +622,7 @@ export class CompositionGraphComponent implements AfterViewInit { this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_PALETTE_COMPONENT_DRAG_START, (dragElement, dragComponent) => { this.dragElement = dragElement; - this.dragComponent = ComponentInstanceFactory.createComponentInstanceFromComponent(dragComponent); + this.dragComponent = ComponentInstanceFactory.createComponentInstanceFromComponent(dragComponent, this.workspaceService.metadata.categories[0].useServiceSubstitutionForNestedServices); }); this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_PALETTE_COMPONENT_DRAG_ACTION, (position: Point) => { diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/utils/composition-graph-palette-utils.ts b/catalog-ui/src/app/ng2/pages/composition/graph/utils/composition-graph-palette-utils.ts index 922f19cb7f..72780ec0e5 100644 --- a/catalog-ui/src/app/ng2/pages/composition/graph/utils/composition-graph-palette-utils.ts +++ b/catalog-ui/src/app/ng2/pages/composition/graph/utils/composition-graph-palette-utils.ts @@ -116,8 +116,7 @@ export class CompositionGraphPaletteUtils { * @param component */ private _createComponentInstanceOnGraphFromPaletteComponent(cy:Cy.Instance, fullComponent:LeftPaletteComponent, event:DragEvent) { - - let componentInstanceToCreate:ComponentInstance = ComponentInstanceFactory.createComponentInstanceFromComponent(fullComponent); + let componentInstanceToCreate:ComponentInstance = ComponentInstanceFactory.createComponentInstanceFromComponent(fullComponent, this.workspaceService.metadata.categories[0].useServiceSubstitutionForNestedServices); let cytoscapePosition:Cy.Position = this.commonGraphUtils.getCytoscapeNodePosition(cy, event); componentInstanceToCreate.posX = cytoscapePosition.x; componentInstanceToCreate.posY = cytoscapePosition.y; diff --git a/catalog-ui/src/app/ng2/pages/composition/palette/services/palette.service.ts b/catalog-ui/src/app/ng2/pages/composition/palette/services/palette.service.ts index 7587c5206f..d1d48507a5 100644 --- a/catalog-ui/src/app/ng2/pages/composition/palette/services/palette.service.ts +++ b/catalog-ui/src/app/ng2/pages/composition/palette/services/palette.service.ts @@ -3,6 +3,7 @@ import { Inject, Injectable } from '@angular/core'; import { LeftPaletteComponent, LeftPaletteMetadataTypes } from 'app/models/components/displayComponent'; import { GroupMetadata } from 'app/models/group-metadata'; import { PolicyMetadata } from 'app/models/policy-metadata'; +import { IComponentMetadata } from 'app/models/component-metadata'; import { SdcConfigToken } from 'app/ng2/config/sdc-config.config'; import { ISdcConfig } from 'app/ng2/config/sdc-config.config.factory'; import { WorkspaceService } from 'app/ng2/pages/workspace/workspace.service'; @@ -75,10 +76,20 @@ export class CompositionPaletteService { private combineResoponses(resInstances: object, resGrouops: object, resPolicies: object) { const retValObject = {}; - // Generic will be the 1st category in the left Pallete + if (resInstances['Generic']) { - retValObject['Generic'] = resInstances['Generic']; - } + if (this.isSubstitutionForNestedServices()) { + const serviceGroup = this.createServiceGroup(resInstances); + if (serviceGroup) { + retValObject['Service'] = serviceGroup; + } + } + else { + // Generic will be the 1st category in the left Pallete + retValObject['Generic'] = resInstances['Generic']; + } + } + // Add all other categories for (const category in resInstances) { if (category === 'Generic') { @@ -95,4 +106,25 @@ export class CompositionPaletteService { return retValObject; } + + private isSubstitutionForNestedServices(): boolean { + return this.workspaceService.metadata.categories[0].useServiceSubstitutionForNestedServices; + } + + private createServiceGroup(resInstances: object): object { + const servicesList = resInstances['Generic']['Generic']; + if (Array.isArray(servicesList) && servicesList.length > 0) { + delete resInstances['Generic']['Generic']; + return servicesList.reduce(function (map, component) { + if (map[component.categories[0].name]) { + map[component.categories[0].name].push(component); + } else { + map[component.categories[0].name] = [component]; + } + return map; + }, {}); + } + return null; + } + } diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/__snapshots__/composition-panel.component.spec.ts.snap b/catalog-ui/src/app/ng2/pages/composition/panel/__snapshots__/composition-panel.component.spec.ts.snap index fdede9d09e..beaa72f4fb 100644 --- a/catalog-ui/src/app/ng2/pages/composition/panel/__snapshots__/composition-panel.component.spec.ts.snap +++ b/catalog-ui/src/app/ng2/pages/composition/panel/__snapshots__/composition-panel.component.spec.ts.snap @@ -9,6 +9,7 @@ exports[`composition-panel component should match current snapshot of compositio isConfiguration={[Function Function]} isPNF={[Function Function]} selectedComponentIsServiceProxyInstance={[Function Function]} + selectedComponentIsServiceSubstitutionInstance={[Function Function]} selectedComponentIsVfcInstance={[Function Function]} setActive={[Function Function]} store={[Function Store]} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.component.ts index bf8cc27bfb..89634ef000 100644 --- a/catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.component.ts +++ b/catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.component.ts @@ -121,29 +121,29 @@ export class CompositionPanelComponent { } // Deployment artifacts - if (!this.isPNF() && !this.isConfiguration() && !this.selectedComponentIsServiceProxyInstance()) { + if (!this.isPNF() && !this.isConfiguration() && !this.selectedComponentIsServiceProxyInstance() && !this.selectedComponentIsServiceSubstitutionInstance()) { this.tabs.push(tabs.deploymentArtifacts); } // Properties or Inputs - if (component.isResource() || this.selectedComponentIsServiceProxyInstance()) { + if (component.isResource() || this.selectedComponentIsServiceProxyInstance() || this.selectedComponentIsServiceSubstitutionInstance()) { this.tabs.push(tabs.properties); } else { this.tabs.push(tabs.inputs); } - if (!this.isConfiguration() && !this.selectedComponentIsServiceProxyInstance()) { + if (!this.isConfiguration() && !this.selectedComponentIsServiceProxyInstance() && !this.selectedComponentIsServiceSubstitutionInstance()) { this.tabs.push(tabs.infoArtifacts); } - if (!(component.isService()) || this.selectedComponentIsServiceProxyInstance()) { + if (!(component.isService()) || this.selectedComponentIsServiceProxyInstance() || this.selectedComponentIsServiceSubstitutionInstance()) { this.tabs.push(tabs.reqAndCapabilities); } - if (component.isService() && !this.selectedComponentIsServiceProxyInstance()) { + if (component.isService() && !this.selectedComponentIsServiceProxyInstance() && !this.selectedComponentIsServiceSubstitutionInstance()) { this.tabs.push(tabs.apiArtifacts); } - if (component.isService() && this.selectedComponentIsServiceProxyInstance()) { + if (component.isService() && (this.selectedComponentIsServiceProxyInstance() || this.selectedComponentIsServiceSubstitutionInstance())) { this.tabs.push(tabs.consumption); this.tabs.push(tabs.dependencies); this.tabs.push(tabs.substitutionFilter) @@ -173,6 +173,10 @@ export class CompositionPanelComponent { private selectedComponentIsServiceProxyInstance = (): boolean => { return this.isComponentInstanceSelected() && this.selectedComponent.isServiceProxy(); } + + private selectedComponentIsServiceSubstitutionInstance = (): boolean => { + return this.isComponentInstanceSelected() && this.selectedComponent.isServiceSubstitution(); + } private selectedComponentIsVfcInstance = (): boolean => { return this.isComponentInstanceSelected() && this.selectedComponent.isVFC(); diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.ts index 45f31e7b35..cb889a2583 100644 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.ts +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.ts @@ -110,7 +110,7 @@ export class InfoTabComponent implements OnInit, OnDestroy { }, onCancel); }; - if (this.component.isService() || this.component.isServiceProxy()) { + if (this.component.isService() || this.component.isServiceProxy() || this.component.isServiceSubstitution()) { this.serviceService.checkComponentInstanceVersionChange(this.workspaceService.metadata.componentType, this.workspaceService.metadata.uniqueId, this.component.uniqueId, newVersionValue).subscribe((pathsToDelete:string[]) => { if (pathsToDelete && pathsToDelete.length) { diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts index 725847bc6d..9fb1a928fe 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts @@ -316,7 +316,8 @@ export class PropertiesAssignmentComponent { this.selectedInstance_FlattenCapabilitiesList, (result, cap: Capability) => { isCapabilityOwnedByInstance = cap.ownerId === currentUniqueId || - selectedComponentInstanceData.isServiceProxy() && cap.ownerId === selectedComponentInstanceData.sourceModelUid; + selectedComponentInstanceData.isServiceProxy() || selectedComponentInstanceData.isServiceSubstitution() && + cap.ownerId === selectedComponentInstanceData.sourceModelUid; if (cap.properties && isCapabilityOwnedByInstance) { _.forEach(cap.properties, prop => { if (!prop.origName) { 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 cf30ea8a75..fde110957f 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 @@ -465,6 +465,7 @@ export class TopologyTemplateService { switch (componentType) { case ComponentType.SERVICE: case ComponentType.SERVICE_PROXY: + case ComponentType.SERVICE_SUBSTITUTION: return ServerTypeUrl.SERVICES; default: return ServerTypeUrl.RESOURCES; diff --git a/catalog-ui/src/app/utils/component-factory.ts b/catalog-ui/src/app/utils/component-factory.ts index d4e282fcb0..5fda9c8db2 100644 --- a/catalog-ui/src/app/utils/component-factory.ts +++ b/catalog-ui/src/app/utils/component-factory.ts @@ -148,6 +148,7 @@ export class ComponentFactory { switch (componentType) { case ComponentType.SERVICE_PROXY: case ComponentType.SERVICE: + case ComponentType.SERVICE_SUBSTITUTION: newComponent = new Service(this.ServiceService, this.$q); break; diff --git a/catalog-ui/src/app/utils/component-instance-factory.ts b/catalog-ui/src/app/utils/component-instance-factory.ts index 03abd96a77..748bd39c9b 100644 --- a/catalog-ui/src/app/utils/component-instance-factory.ts +++ b/catalog-ui/src/app/utils/component-instance-factory.ts @@ -22,7 +22,7 @@ */ 'use strict'; import { ComponentType } from 'app/utils'; -import { Component, ComponentInstance, ResourceInstance, ServiceInstance, ServiceProxyInstance } from '../models'; +import { Component, ComponentInstance, ResourceInstance, ServiceInstance, ServiceSubstitutionInstance, ServiceProxyInstance } from '../models'; import { LeftPaletteComponent } from '../models/components/displayComponent'; export class ComponentInstanceFactory { @@ -36,6 +36,9 @@ export class ComponentInstanceFactory { case ComponentType.SERVICE_PROXY: newComponentInstance = new ServiceProxyInstance(componentInstance); break; + case ComponentType.SERVICE_SUBSTITUTION: + newComponentInstance = new ServiceSubstitutionInstance(componentInstance); + break; default : newComponentInstance = new ResourceInstance(componentInstance); break; @@ -52,6 +55,9 @@ export class ComponentInstanceFactory { case ComponentType.SERVICE_PROXY: newComponentInstance = new ServiceProxyInstance(); break; + case ComponentType.SERVICE_SUBSTITUTION: + newComponentInstance = new ServiceSubstitutionInstance(); + break; default : newComponentInstance = new ResourceInstance(); break; @@ -59,7 +65,7 @@ export class ComponentInstanceFactory { return newComponentInstance; } - static createComponentInstanceFromComponent = (component: LeftPaletteComponent): ComponentInstance => { + static createComponentInstanceFromComponent = (component: LeftPaletteComponent, useServiceSubstitutionForNestedServices?: boolean): ComponentInstance => { const newComponentInstance: ComponentInstance = ComponentInstanceFactory.createEmptyComponentInstance(component.componentType); newComponentInstance.uniqueId = component.uniqueId + (new Date()).getTime(); newComponentInstance.posX = 0; @@ -78,7 +84,11 @@ export class ComponentInstanceFactory { return component.componentSubType; } else { if (component.componentType === ComponentType.SERVICE) { - return ComponentType.SERVICE_PROXY; + if (useServiceSubstitutionForNestedServices){ + return ComponentType.SERVICE_SUBSTITUTION; + } else { + return ComponentType.SERVICE_PROXY; + } } else { return component.resourceType; } diff --git a/catalog-ui/src/app/utils/constants.ts b/catalog-ui/src/app/utils/constants.ts index a4bceb5ded..c7947748c8 100644 --- a/catalog-ui/src/app/utils/constants.ts +++ b/catalog-ui/src/app/utils/constants.ts @@ -39,6 +39,7 @@ export class ComponentType { static RESOURCE = 'RESOURCE'; static RESOURCE_INSTANCE = 'RESOURCE_INSTANCE'; static SERVICE_PROXY = 'ServiceProxy' + static SERVICE_SUBSTITUTION = 'ServiceSubstitution' } export class ServerTypeUrl { diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/category/CategoryDataDefinition.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/category/CategoryDataDefinition.java index 27d6ae56fa..cf0117f74a 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/category/CategoryDataDefinition.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/category/CategoryDataDefinition.java @@ -21,114 +21,32 @@ package org.openecomp.sdc.be.datatypes.category; import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition; - +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import lombok.NoArgsConstructor; import java.util.List; +@Getter +@Setter +@EqualsAndHashCode(callSuper = false) +@ToString +@NoArgsConstructor public class CategoryDataDefinition extends ToscaDataDefinition { private String name; private String normalizedName; private String uniqueId; private List icons; - - public CategoryDataDefinition() { - - } + private boolean useServiceSubstitutionForNestedServices = false; public CategoryDataDefinition(CategoryDataDefinition c) { this.name = c.name; this.normalizedName = c.normalizedName; this.uniqueId = c.uniqueId; this.icons = c.icons; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getNormalizedName() { - return normalizedName; - } - - public void setNormalizedName(String normalizedName) { - this.normalizedName = normalizedName; - } - - public String getUniqueId() { - return uniqueId; - } - - public void setUniqueId(String uniqueId) { - this.uniqueId = uniqueId; - } - - public List getIcons() { - return icons; - } - - public void setIcons(List icons) { - this.icons = icons; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((name == null) ? 0 : name.hashCode()); - result = prime * result + ((normalizedName == null) ? 0 : normalizedName.hashCode()); - result = prime * result + ((uniqueId == null) ? 0 : uniqueId.hashCode()); - result = prime * result + ((icons == null) ? 0 : icons.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - CategoryDataDefinition other = (CategoryDataDefinition) obj; - if (name == null) { - if (other.name != null) { - return false; - } - } else if (!name.equals(other.name)) { - return false; - } - if (normalizedName == null) { - if (other.normalizedName != null) { - return false; - } - } else if (!normalizedName.equals(other.normalizedName)) { - return false; - } - if (uniqueId == null) { - if (other.uniqueId != null) { - return false; - } - } else if (!uniqueId.equals(other.uniqueId)) { - return false; - } - if (icons == null) { - return other.icons == null; - } else { - return icons.equals(other.icons); - } - } - - @Override - public String toString() { - return "CategoryDataDefinition [name=" + name + ", normalizedName=" + normalizedName + ", uniqueId=" + uniqueId - + ", icons=" + icons + "]"; + this.useServiceSubstitutionForNestedServices = c.useServiceSubstitutionForNestedServices; } } diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/GraphPropertyEnum.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/GraphPropertyEnum.java index 09e1de6c7b..296b0067b8 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/GraphPropertyEnum.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/GraphPropertyEnum.java @@ -50,7 +50,7 @@ public enum GraphPropertyEnum { LAST_LOGIN_TIME("lastLoginTime", Long.class, false, false), //used for category (old format, no json for categories) ICONS("icons", String.class, false, false), - + USE_SUBSTITUTION_FOR_NESTED_SERVICES("useServiceSubstitutionForNestedServices", Boolean.class, false, false), //Archive/Restore IS_ARCHIVED("isArchived", Boolean.class, false, true), IS_VSP_ARCHIVED("isVspArchived", Boolean.class, false, true), diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/OriginTypeEnum.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/OriginTypeEnum.java index 48394013de..5e709054a4 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/OriginTypeEnum.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/OriginTypeEnum.java @@ -27,7 +27,8 @@ public enum OriginTypeEnum { CVFC("CVFC", "CVFC (Complex Virtual Function Component)", "resource instance", ComponentTypeEnum.RESOURCE, false), PNF("PNF", "PNF (Physical Network Function)", "resource instance", ComponentTypeEnum.RESOURCE, false), CR("CR", "CR (Complex Resource)", "resource instance", ComponentTypeEnum.RESOURCE, false), - ServiceProxy("Service Proxy", "Service Proxy", "service proxy", ComponentTypeEnum.RESOURCE, false); + ServiceProxy("Service Proxy", "Service Proxy", "service proxy", ComponentTypeEnum.RESOURCE, false), + ServiceSubstitution("Service Substitution", "Service Substitution", "service substitution", ComponentTypeEnum.RESOURCE, false); private String value; private String displayValue; diff --git a/common-be/src/test/java/org/openecomp/sdc/be/datatypes/category/CategoryDataDefinitionTest.java b/common-be/src/test/java/org/openecomp/sdc/be/datatypes/category/CategoryDataDefinitionTest.java index 6422e5564d..2cb0261a67 100644 --- a/common-be/src/test/java/org/openecomp/sdc/be/datatypes/category/CategoryDataDefinitionTest.java +++ b/common-be/src/test/java/org/openecomp/sdc/be/datatypes/category/CategoryDataDefinitionTest.java @@ -20,10 +20,8 @@ package org.openecomp.sdc.be.datatypes.category; -import org.junit.Assert; import org.junit.Test; -import java.util.List; public class CategoryDataDefinitionTest { @@ -35,137 +33,10 @@ public class CategoryDataDefinitionTest { @Test public void testCopyConstructor() throws Exception { CategoryDataDefinition testSubject; - String result; // default test testSubject = createTestSubject(); CategoryDataDefinition categoryDataDefinition = new CategoryDataDefinition(testSubject); } - @Test - public void testGetName() throws Exception { - CategoryDataDefinition testSubject; - String result; - - // default test - testSubject = createTestSubject(); - result = testSubject.getName(); - } - - - @Test - public void testSetName() throws Exception { - CategoryDataDefinition testSubject; - String name = ""; - - // default test - testSubject = createTestSubject(); - testSubject.setName(name); - } - - - @Test - public void testGetNormalizedName() throws Exception { - CategoryDataDefinition testSubject; - String result; - - // default test - testSubject = createTestSubject(); - result = testSubject.getNormalizedName(); - } - - - @Test - public void testSetNormalizedName() throws Exception { - CategoryDataDefinition testSubject; - String normalizedName = ""; - - // default test - testSubject = createTestSubject(); - testSubject.setNormalizedName(normalizedName); - } - - - @Test - public void testGetUniqueId() throws Exception { - CategoryDataDefinition testSubject; - String result; - - // default test - testSubject = createTestSubject(); - result = testSubject.getUniqueId(); - } - - - @Test - public void testSetUniqueId() throws Exception { - CategoryDataDefinition testSubject; - String uniqueId = ""; - - // default test - testSubject = createTestSubject(); - testSubject.setUniqueId(uniqueId); - } - - - @Test - public void testGetIcons() throws Exception { - CategoryDataDefinition testSubject; - List result; - - // default test - testSubject = createTestSubject(); - result = testSubject.getIcons(); - } - - - @Test - public void testSetIcons() throws Exception { - CategoryDataDefinition testSubject; - List icons = null; - - // default test - testSubject = createTestSubject(); - testSubject.setIcons(icons); - } - - - @Test - public void testHashCode() throws Exception { - CategoryDataDefinition testSubject; - int result; - - // default test - testSubject = createTestSubject(); - result = testSubject.hashCode(); - } - - - @Test - public void testEquals() throws Exception { - CategoryDataDefinition testSubject; - Object obj = null; - boolean result; - - // test 1 - testSubject = createTestSubject(); - obj = null; - result = testSubject.equals(obj); - Assert.assertEquals(false, result); - result = testSubject.equals(testSubject); - Assert.assertEquals(true, result); - result = testSubject.equals(new CategoryDataDefinition(testSubject)); - Assert.assertEquals(true, result); - } - - - @Test - public void testToString() throws Exception { - CategoryDataDefinition testSubject; - String result; - - // default test - testSubject = createTestSubject(); - result = testSubject.toString(); - } } diff --git a/openecomp-ui/yarn.lock b/openecomp-ui/yarn.lock index 30eeda9850..7117631e6a 100644 --- a/openecomp-ui/yarn.lock +++ b/openecomp-ui/yarn.lock @@ -5198,6 +5198,19 @@ html-webpack-plugin@^2.30.1: pretty-error "^2.0.2" toposort "^1.0.0" +html-webpack-plugin@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz#b01abbd723acaaa7b37b6af4492ebda03d9dd37b" + integrity sha1-sBq71yOsqqeze2r0SS69oD2d03s= + dependencies: + html-minifier "^3.2.3" + loader-utils "^0.2.16" + lodash "^4.17.3" + pretty-error "^2.0.2" + tapable "^1.0.0" + toposort "^1.0.0" + util.promisify "1.0.0" + htmlparser2@3.8.x: version "3.8.3" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.8.3.tgz#996c28b191516a8be86501a7d79757e5c70c1068" @@ -10642,6 +10655,14 @@ util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" +util.promisify@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== + dependencies: + define-properties "^1.1.2" + object.getownpropertydescriptors "^2.0.3" + util@0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" -- 2.16.6