aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichaelMorris <michael.morris@est.tech>2020-06-23 09:15:48 +0100
committerSébastien Determe <sebastien.determe@intl.att.com>2020-09-04 14:42:04 +0000
commit032525a375681fb18cc498d8daed9d73faa21ec3 (patch)
tree20cf4c17f406b8d30c29ce904fe1f19ea4a2c989
parentc16117e08b97da93da61be841c22f5759cdadd37 (diff)
Support for Nested/Hierarchical Services
Change-Id: I478cf2e1f9cf96443a3e35bf22ac2c9d72bca8f1 Issue-ID: SDC-3145 Signed-off-by: MichaelMorris <michael.morris@est.tech>
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CategoriesImportManager.java5
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java149
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java38
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/CategoriesImportManagerTest.java20
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogicTest.java78
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java32
-rw-r--r--catalog-be/src/test/resources/types/categoryTypes.yml8
-rw-r--r--catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java1
-rw-r--r--catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/category/CategoryData.java6
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperation.java4
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/TopologyTemplateOperation.java2
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementOperation.java1
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java12
-rw-r--r--catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacadeTest.java42
-rw-r--r--catalog-ui/cypress/fixtures/common/setup-ui.json1
-rw-r--r--catalog-ui/src/app/models.ts2
-rw-r--r--catalog-ui/src/app/models/category.ts1
-rw-r--r--catalog-ui/src/app/models/components/displayComponent.ts2
-rw-r--r--catalog-ui/src/app/models/componentsInstances/componentInstance.ts6
-rw-r--r--catalog-ui/src/app/models/componentsInstances/fullComponentInstance.ts2
-rw-r--r--catalog-ui/src/app/models/componentsInstances/serviceSubstitutionInstance.ts30
-rw-r--r--catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-service-substitution.ts59
-rw-r--r--catalog-ui/src/app/models/graph/nodes/nodes-factory.ts12
-rw-r--r--catalog-ui/src/app/ng2/components/ui/sdc-element-icon/sdc-element-icon.component.ts1
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.ts2
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/utils/composition-graph-palette-utils.ts3
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/palette/services/palette.service.ts38
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/__snapshots__/composition-panel.component.spec.ts.snap1
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.component.ts16
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.ts2
-rw-r--r--catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts3
-rw-r--r--catalog-ui/src/app/ng2/services/component-services/topology-template.service.ts1
-rw-r--r--catalog-ui/src/app/utils/component-factory.ts1
-rw-r--r--catalog-ui/src/app/utils/component-instance-factory.ts16
-rw-r--r--catalog-ui/src/app/utils/constants.ts1
-rw-r--r--common-be/src/main/java/org/openecomp/sdc/be/datatypes/category/CategoryDataDefinition.java106
-rw-r--r--common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/GraphPropertyEnum.java2
-rw-r--r--common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/OriginTypeEnum.java3
-rw-r--r--common-be/src/test/java/org/openecomp/sdc/be/datatypes/category/CategoryDataDefinitionTest.java129
-rw-r--r--openecomp-ui/yarn.lock21
40 files changed, 551 insertions, 308 deletions
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<Component, StorageOperationStatus> 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<Component, StorageOperationStatus> 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<Component, StorageOperationStatus> getServiceResult = toscaOperationFacade.getToscaFullElement(resourceInstance.getComponentUid());
+ if (getServiceResult.isRight()) {
+ throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(getServiceResult.right().value()));
+ }
+ final Component service = getServiceResult.left().value();
+
+ final Either<Component, StorageOperationStatus> 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<String, List<CapabilityDefinition>> capabilities = service.getCapabilities();
+ final Component service = serviceRes.left().value();
+ final Map<String, List<CapabilityDefinition>> capabilities = service.getCapabilities();
resourceInstance.setCapabilities(capabilities);
- Map<String, List<RequirementDefinition>> req = service.getRequirements();
+ final Map<String, List<RequirementDefinition>> req = service.getRequirements();
resourceInstance.setRequirements(req);
- Map<String, InterfaceDefinition> serviceInterfaces = service.getInterfaces();
+ final Map<String, InterfaceDefinition> serviceInterfaces = service.getInterfaces();
if(MapUtils.isNotEmpty(serviceInterfaces)) {
serviceInterfaces.forEach(resourceInstance::addInterface);
}
-
-
resourceInstance.setProperties(PropertiesUtils.getProperties(service));
- List<InputDefinition> serviceInputs = service.getInputs();
+ final List<InputDefinition> 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<Component, StorageOperationStatus> 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<Component, StorageOperationStatus> getServiceResult = toscaOperationFacade.getToscaFullElement(newComponentInstance.getComponentUid());
+ if (getServiceResult.isRight()) {
+ throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(getServiceResult.right().value()));
+ }
+ final Component service = getServiceResult.left().value();
+
+ final Either<Component, StorageOperationStatus> 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<Map<String, Object>, 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<Component, StorageOperationStatus> 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<String, Component> componentCache,
+ final Component container, final ToscaTemplate toscaNode) {
+ final List<ComponentInstance> componentInstances = container.getComponentInstances();
+
+ if (CollectionUtils.isEmpty(componentInstances)) {
+ return;
+ }
+ final List<ComponentInstance> 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<String, ToscaNodeType> nodeTypes = toscaNode.getNode_types() == null ? new HashMap<>() : toscaNode.getNode_types();
+ convertInterfaceNodeType(new HashMap<>(), componentCache.get(inst.getSourceModelUid()), toscaNode, nodeTypes, true);
+ }
+ }
+ }
private ToscaNodeType createProxyNodeType(Map<String, Component> componentCache, Component origComponent,
Component proxyComponent, ComponentInstance instance) {
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<Map<String, List<CategoryDefinition>>, ResponseFormat> createCapabilityTypes = importManager.createCategories(ymlContent);
- assertTrue(createCapabilityTypes.isLeft());
+
+ assertTrue(createCapabilityTypes.isLeft());
+ final Map<String, List<CategoryDefinition>> categories = createCapabilityTypes.left().value();
+ final Optional<CategoryDefinition> categoryVoIPCallControl = categories.get("services").stream().filter(category -> category.getName().equals("VoIP Call Control")).findAny();
+ final Optional<CategoryDefinition> categoryWithServiceSubstitutionTrue = categories.get("services").stream().filter(category -> category.getName().equals("Category With Service Substitution True")).findAny();
+ final Optional<CategoryDefinition> 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<ComponentInstance, Resource> 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<String, Component> 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<ComponentInstance> 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<List<String>>() {
}.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<String, StorageOperationStatus> 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<List<String>>() {}.getType();
List<String> 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<ImmutablePair<TopologyTemplate, String>, 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<ComponentInstance> 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<ImmutablePair<Component, String>, 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<PolicyDefinition, StorageOperationStatus> 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<ISubCategory>;
+ 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 = (<Service>originComponent).serviceApiArtifacts;
this.serviceType = (<Service>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<String> 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<String> getIcons() {
- return icons;
- }
-
- public void setIcons(List<String> 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<String> result;
-
- // default test
- testSubject = createTestSubject();
- result = testSubject.getIcons();
- }
-
-
- @Test
- public void testSetIcons() throws Exception {
- CategoryDataDefinition testSubject;
- List<String> 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"