Support for Nested/Hierarchical Services

Change-Id: I478cf2e1f9cf96443a3e35bf22ac2c9d72bca8f1
Issue-ID: SDC-3145
Signed-off-by: MichaelMorris <michael.morris@est.tech>
diff --git a/catalog-ui/cypress/fixtures/common/setup-ui.json b/catalog-ui/cypress/fixtures/common/setup-ui.json
index cdc8b0b..2c619a3 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 91fa4a7..ad201e2 100644
--- a/catalog-ui/src/app/models.ts
+++ b/catalog-ui/src/app/models.ts
@@ -42,6 +42,7 @@
 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-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 0d5c63b..15df985 100644
--- a/catalog-ui/src/app/models/category.ts
+++ b/catalog-ui/src/app/models/category.ts
@@ -37,6 +37,7 @@
 
 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 4e94695..2e89bd0 100644
--- a/catalog-ui/src/app/models/components/displayComponent.ts
+++ b/catalog-ui/src/app/models/components/displayComponent.ts
@@ -28,6 +28,7 @@
 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 @@
     }
 
     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 e311589..e91fcc9 100644
--- a/catalog-ui/src/app/models/componentsInstances/componentInstance.ts
+++ b/catalog-ui/src/app/models/componentsInstances/componentInstance.ts
@@ -157,13 +157,17 @@
     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 ab9015d..50a9eeb 100644
--- a/catalog-ui/src/app/models/componentsInstances/fullComponentInstance.ts
+++ b/catalog-ui/src/app/models/componentsInstances/fullComponentInstance.ts
@@ -66,7 +66,7 @@
         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 0000000..6f91a62
--- /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 0000000..94f85e3
--- /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 fbcd479..57b245e 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 @@
     NodeUcpe,
     CompositionCiNodeService,
     CompositionCiNodeServiceProxy,
+    CompositionCiNodeServiceSubstitution,
     CompositionCiNodeBase,
     ComponentInstance,
     CompositionCiNodeVfc
@@ -41,10 +42,10 @@
 @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 @@
         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 @@
         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 dd48af2..fc81a5b 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 @@
                 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 5467ece..45a7d4c 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 @@
 
         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 922f19c..72780ec 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 @@
      * @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 7587c52..d1d4850 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 { 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 @@
 
     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 @@
 
         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 fdede9d..beaa72f 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 @@
   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 bf8cc27..89634ef 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 @@
         }
 
         // 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 @@
     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 45f31e7..cb889a2 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 @@
                     }, 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 725847b..9fb1a92 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 @@
             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 cf30ea8..fde1109 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 @@
         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 d4e282f..5fda9c8 100644
--- a/catalog-ui/src/app/utils/component-factory.ts
+++ b/catalog-ui/src/app/utils/component-factory.ts
@@ -148,6 +148,7 @@
         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 03abd96..748bd39 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 @@
            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 @@
             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 @@
         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 @@
                 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 a4bceb5..c794774 100644
--- a/catalog-ui/src/app/utils/constants.ts
+++ b/catalog-ui/src/app/utils/constants.ts
@@ -39,6 +39,7 @@
     static RESOURCE = 'RESOURCE';
     static RESOURCE_INSTANCE = 'RESOURCE_INSTANCE';
     static SERVICE_PROXY = 'ServiceProxy'
+    static SERVICE_SUBSTITUTION = 'ServiceSubstitution'
 }
 
 export class ServerTypeUrl {