[CORD-1250] Rendering new ServiceInstance Models

Change-Id: Ic8fdb4775b119816b4b7aa085e6af699eaa13a67
diff --git a/src/app/core/services/helpers/config.helpers.ts b/src/app/core/services/helpers/config.helpers.ts
index c495ba5..b49b27c 100644
--- a/src/app/core/services/helpers/config.helpers.ts
+++ b/src/app/core/services/helpers/config.helpers.ts
@@ -73,7 +73,7 @@
     pluralize.addPluralRule(/library$/i, 'librarys');
     pluralize.addPluralRule(/imagedeployments/i, 'imagedeploymentses');
     pluralize.addPluralRule(/controllerimages/i, 'controllerimageses');
-    pluralize.addPluralRule(/servicedependency/i, 'servicedependencys');
+    pluralize.addPluralRule(/servicedependency/i, 'servicedependencies');
   }
 
   public pluralize(string: string, quantity?: number, count?: boolean): string {
diff --git a/src/app/service-graph/components/coarse/coarse.component.ts b/src/app/service-graph/components/coarse/coarse.component.ts
index ac687d0..501c543 100644
--- a/src/app/service-graph/components/coarse/coarse.component.ts
+++ b/src/app/service-graph/components/coarse/coarse.component.ts
@@ -2,7 +2,7 @@
 import * as d3 from 'd3';
 import * as $ from 'jquery';
 import * as _ from 'lodash';
-import {IXosServiceGraphStore} from '../../services/graph.store';
+import {IXosServiceGraphStore} from '../../services/service-graph.store';
 import {IXosServiceGraph, IXosServiceGraphNode, IXosServiceGraphLink} from '../../interfaces';
 import {XosServiceGraphConfig as config} from '../../graph.config';
 import {IXosDebouncer} from '../../../core/services/helpers/debounce.helper';
@@ -177,6 +177,7 @@
     const entering = node.enter()
       .append('g')
       .attr({
+        id: n => n.id,
         class: n => `node ${this.XosGraphHelpers.parseElemClasses(n.d3Class)}`,
         transform: `translate(${svgDim.width / 2}, ${svgDim.height / 2})`
       })
@@ -232,6 +233,7 @@
 
     entering.append('line')
       .attr({
+        id: n => n.id,
         class: l => `link ${this.XosGraphHelpers.parseElemClasses(l.d3Class)}`,
         'marker-start': 'url(#arrow)'
       });
diff --git a/src/app/service-graph/components/fine-grained/fine-grained.component.scss b/src/app/service-graph/components/fine-grained/fine-grained.component.scss
index c7fcfbc..37605f9 100644
--- a/src/app/service-graph/components/fine-grained/fine-grained.component.scss
+++ b/src/app/service-graph/components/fine-grained/fine-grained.component.scss
@@ -41,7 +41,7 @@
         stroke: blue;
       }
 
-      &.tenant > rect{
+      &.tenant, &.serviceinstance > rect{
         stroke: green;
       }
 
@@ -60,6 +60,15 @@
   .link-group {
     line {
       stroke: $color-accent;
+
+      &.ext-service-instance {
+        stroke: green;
+      }
+
+      &.ext-owner {
+        stroke: green;
+        stroke-dasharray: 5;
+      }
     }
   }
   .arrow-marker {
diff --git a/src/app/service-graph/components/fine-grained/fine-grained.component.ts b/src/app/service-graph/components/fine-grained/fine-grained.component.ts
index 3fc47a5..6d57aad 100644
--- a/src/app/service-graph/components/fine-grained/fine-grained.component.ts
+++ b/src/app/service-graph/components/fine-grained/fine-grained.component.ts
@@ -1,4 +1,3 @@
-import {IXosServiceGraphStore} from '../../services/graph.store';
 import './fine-grained.component.scss';
 import * as d3 from 'd3';
 import * as $ from 'jquery';
@@ -11,11 +10,12 @@
 import {IXosSidePanelService} from '../../../core/side-panel/side-panel.service';
 import {IXosGraphHelpers} from '../../services/d3-helpers/graph.helpers';
 import {IXosServiceGraphExtender, IXosServiceGraphReducer} from '../../services/graph.extender';
+import {IXosServiceInstanceGraphStore} from '../../services/service-instance.graph.store';
 
 class XosFineGrainedTenancyGraphCtrl {
   static $inject = [
     '$log',
-    'XosServiceGraphStore',
+    'XosServiceInstanceGraphStore',
     'XosDebouncer',
     'XosModelDiscoverer',
     'XosSidePanel',
@@ -39,7 +39,7 @@
 
   constructor(
     private $log: ng.ILogService,
-    private XosServiceGraphStore: IXosServiceGraphStore,
+    private XosServiceInstanceGraphStore: IXosServiceInstanceGraphStore,
     private XosDebouncer: IXosDebouncer,
     private XosModelDiscoverer: IXosModelDiscovererService,
     private XosSidePanel: IXosSidePanelService,
@@ -56,10 +56,10 @@
       this.renderGraph();
     });
 
-    this.GraphSubscription = this.XosServiceGraphStore.get()
+    this.GraphSubscription = this.XosServiceInstanceGraphStore.get()
       .subscribe(
         (graph) => {
-          this.$log.debug(`[XosFineGrainedTenancyGraphCtrl] Fine-Grained Event and render`, graph);
+          this.$log.debug(`[XosServiceInstanceGraphStore] Fine-Grained Event and render`, graph);
 
           if (!graph || !graph.nodes || !graph.links) {
             return;
@@ -159,9 +159,6 @@
         });
     };
     const getLinkStrenght = (l: IXosServiceGraphLink) => {
-      if (l.id.indexOf('service') > -1) {
-        return 0.1;
-      }
       return 1;
     };
     const svgDim = this.getSvgDimensions();
@@ -311,6 +308,7 @@
     const entering = node.enter()
       .append('g')
       .attr({
+        id: n => n.id,
         class: n => `node ${n.type} ${this.XosGraphHelpers.parseElemClasses(n.d3Class)}`,
         transform: (n, i) => `translate(${hStep * i}, ${vStep * i})`
       })
@@ -343,10 +341,10 @@
       });
 
     this.renderServiceNodes(entering.filter('.service'));
-    this.renderTenantNodes(entering.filter('.tenant'));
+    this.renderTenantNodes(entering.filter('.serviceinstance'));
     this.renderNetworkNodes(entering.filter('.network'));
     this.renderSubscriberNodes(entering.filter('.subscriber'));
-    this.renderSubscriberNodes(entering.filter('.tenantroot'));
+    // this.renderSubscriberNodes(entering.filter('.tenantroot'));
   }
 
   private renderLinks(links: IXosServiceGraphLink[]) {
@@ -358,6 +356,7 @@
 
     entering.append('line')
       .attr({
+        id: n => n.id,
         class: n => `link ${this.XosGraphHelpers.parseElemClasses(n.d3Class)}`,
         'marker-start': 'url(#arrow)'
       });
diff --git a/src/app/service-graph/index.ts b/src/app/service-graph/index.ts
index 00cf9e8..0786592 100644
--- a/src/app/service-graph/index.ts
+++ b/src/app/service-graph/index.ts
@@ -1,15 +1,17 @@
 import {xosDataSources} from '../datasources/index';
-import {XosServiceGraphStore} from './services/graph.store';
+import {XosServiceGraphStore} from './services/service-graph.store';
 import {xosCore} from '../core/index';
 import {XosCoarseTenancyGraph} from './components/coarse/coarse.component';
 import {XosFineGrainedTenancyGraph} from './components/fine-grained/fine-grained.component';
 import {XosServiceGraphExtender, IXosServiceGraphExtender} from './services/graph.extender';
 import {XosGraphHelpers} from './services/d3-helpers/graph.helpers';
+import {XosServiceInstanceGraphStore} from './services/service-instance.graph.store';
 export const xosServiceGraph = 'xosServiceGraph';
 
 angular
   .module(xosServiceGraph, [xosDataSources, xosCore])
   .service('XosServiceGraphStore', XosServiceGraphStore)
+  .service('XosServiceInstanceGraphStore', XosServiceInstanceGraphStore)
   .service('XosServiceGraphExtender', XosServiceGraphExtender)
   .service('XosGraphHelpers', XosGraphHelpers)
   .component('xosCoarseTenancyGraph', XosCoarseTenancyGraph)
diff --git a/src/app/service-graph/interfaces.ts b/src/app/service-graph/interfaces.ts
index 4120bdb..a7e41f1 100644
--- a/src/app/service-graph/interfaces.ts
+++ b/src/app/service-graph/interfaces.ts
@@ -41,15 +41,23 @@
 
 export interface IXosCoarseGraphData {
   services: IXosServiceModel[];
-  servicedependencys: any[];
+  servicedependencies: any[];
 }
 
+// TODO outdated, remove
 export interface IXosFineGrainedGraphData extends IXosCoarseGraphData {
   tenants: IXosTenantModel[];
   subscribers: any[];
   networks: any[];
 }
 
+export interface IXosServiceInstanceGraphData {
+  serviceGraph: IXosServiceGraph;
+  serviceInstances: any[];
+  serviceInstanceLinks: any[];
+  networks: any[];
+}
+
 export interface IXosServiceGraphNodeBadge {
   type: 'info'|'success'|'warning'|'danger';
   text: string;
diff --git a/src/app/service-graph/services/graph.store.ts b/src/app/service-graph/services/graph.store.ts
deleted file mode 100644
index 7c6e552..0000000
--- a/src/app/service-graph/services/graph.store.ts
+++ /dev/null
@@ -1,324 +0,0 @@
-import * as _ from 'lodash';
-import {Observable, BehaviorSubject, Subscription} from 'rxjs';
-import {IXosModelStoreService} from '../../datasources/stores/model.store';
-import {
-  IXosServiceGraph, IXosServiceModel, IXosTenantModel, IXosCoarseGraphData,
-  IXosServiceGraphNode, IXosServiceGraphLink, IXosFineGrainedGraphData
-} from '../interfaces';
-import {IXosDebouncer} from '../../core/services/helpers/debounce.helper';
-export interface IXosServiceGraphStore {
-  get(): Observable<IXosServiceGraph>;
-  getCoarse(): Observable<IXosServiceGraph>;
-}
-
-export class XosServiceGraphStore implements IXosServiceGraphStore {
-  static $inject = [
-    '$log',
-    'XosModelStore',
-    'XosDebouncer'
-  ];
-
-  // graph data store
-  private graphData: BehaviorSubject<IXosFineGrainedGraphData> = new BehaviorSubject({
-    services: [],
-    tenants: [],
-    networks: [],
-    subscribers: [],
-    servicedependencys: []
-  });
-
-  private emptyGraph: IXosServiceGraph = {
-    nodes: [],
-    links: []
-  };
-
-  // representation of the graph as D3 requires
-  private d3CoarseGraph = new BehaviorSubject(this.emptyGraph);
-  private d3FineGrainedGraph = new BehaviorSubject(this.emptyGraph);
-
-  // storing locally reference to the data model
-  private services;
-  private tenants;
-  private subscribers;
-  private networks;
-  private servicedependencys;
-
-  // debounced functions
-  private handleData;
-
-  // datastore
-  private ServiceSubscription: Subscription;
-  private TenantSubscription: Subscription;
-  private SubscriberSubscription: Subscription;
-  private NetworkSubscription: Subscription;
-  private ServiceDependencySubscription: Subscription;
-
-  constructor (
-    private $log: ng.ILogService,
-    private XosModelStore: IXosModelStoreService,
-    private XosDebouncer: IXosDebouncer
-  ) {
-
-    this.$log.info(`[XosServiceGraphStore] Setup`);
-
-    // we want to have a quiet period of 500ms from the last event before doing anything
-    this.handleData = this.XosDebouncer.debounce(this._handleData, 500, this, false);
-
-    // observe models and populate graphData
-    this.ServiceSubscription = this.XosModelStore.query('Service', '/core/services')
-      .subscribe(
-        (res) => {
-          this.combineData(res, 'services');
-        },
-        (err) => {
-          this.$log.error(`[XosServiceGraphStore] Service Observable: `, err);
-        }
-      );
-
-    this.ServiceDependencySubscription = this.XosModelStore.query('ServiceDependency', '/core/servicedependencys')
-      .subscribe(
-        (res) => {
-          this.combineData(res, 'servicedependencys');
-        },
-        (err) => {
-          this.$log.error(`[XosServiceGraphStore] Service Observable: `, err);
-        }
-      );
-
-    this.TenantSubscription = this.XosModelStore.query('Tenant', '/core/tenants')
-      .subscribe(
-        (res) => {
-          this.combineData(res, 'tenants');
-        },
-        (err) => {
-          this.$log.error(`[XosServiceGraphStore] Tenant Observable: `, err);
-        }
-      );
-
-    this.SubscriberSubscription = this.XosModelStore.query('Tenantroot', '/core/tenantroots')
-      .subscribe(
-        (res) => {
-          this.combineData(res, 'subscribers');
-        },
-        (err) => {
-          this.$log.error(`[XosServiceGraphStore] Subscriber Observable: `, err);
-        }
-      );
-
-    this.NetworkSubscription = this.XosModelStore.query('Network', '/core/networks')
-      .subscribe(
-        (res) => {
-          this.combineData(res, 'networks');
-        },
-        (err) => {
-          this.$log.error(`[XosServiceGraphStore] graphData Observable: `, err);
-        }
-      );
-
-    // observe graphData and build Coarse and FineGrained graphs
-    this.graphData
-      .subscribe(
-        (res: IXosFineGrainedGraphData) => {
-          this.$log.debug(`[XosServiceGraphStore] New graph data received`, res);
-          this.graphDataToCoarseGraph(res);
-          this.graphDataToFineGrainedGraph(res);
-        },
-        (err) => {
-          this.$log.error(`[XosServiceGraphStore] graphData Observable: `, err);
-        }
-      );
-  }
-
-  public get() {
-    return this.d3FineGrainedGraph.asObservable();
-  }
-
-  public getCoarse() {
-    return this.d3CoarseGraph.asObservable();
-  }
-
-  private combineData(data: any, type: 'services'|'tenants'|'subscribers'|'networks'|'servicedependencys') {
-    switch (type) {
-      case 'services':
-        this.services = data;
-        break;
-      case 'tenants':
-        this.tenants = data;
-        break;
-      case 'subscribers':
-        this.subscribers = data;
-        break;
-      case 'networks':
-        this.networks = data;
-        break;
-      case 'servicedependencys':
-        this.servicedependencys = data;
-        break;
-    }
-    this.handleData(this.services, this.tenants);
-  }
-
-  private _handleData(services: IXosServiceModel[], tenants: IXosTenantModel[]) {
-    this.graphData.next({
-      services: this.services,
-      tenants: this.tenants,
-      subscribers: this.subscribers,
-      networks: this.networks,
-      servicedependencys: this.servicedependencys
-    });
-  }
-
-  private getNodeIndexById(id: number | string, nodes: IXosServiceModel[]) {
-    return _.findIndex(nodes, {id: id});
-  }
-
-  private d3Id(type: string, id: number) {
-    return `${type.toLowerCase()}~${id}`;
-  }
-
-  private getTargetId(tenant: IXosTenantModel) {
-
-    let targetId;
-    if (tenant.subscriber_service_id) {
-      targetId = this.d3Id('service', tenant.subscriber_service_id);
-    }
-    else if (tenant.subscriber_tenant_id) {
-      targetId = this.d3Id('tenant', tenant.subscriber_tenant_id);
-    }
-    else if (tenant.subscriber_network_id) {
-      targetId = this.d3Id('network', tenant.subscriber_network_id);
-    }
-    else if (tenant.subscriber_root_id) {
-      // FIXME understand what's the correct model for the subscriber
-      targetId = this.d3Id('tenantroot', tenant.subscriber_root_id);
-    }
-    return targetId;
-  }
-
-  private getSourceId(tenant: IXosTenantModel) {
-    return this.d3Id('service', tenant.provider_service_id);
-  }
-
-  private getNodeType(n: any) {
-    return n.class_names.split(',')[0].toLowerCase();
-  }
-
-  private getNodeLabel(n: any) {
-    if (this.getNodeType(n) === 'tenant') {
-      return n.id;
-    }
-    return n.humanReadableName ? n.humanReadableName : n.name;
-  }
-
-  private removeUnwantedFineGrainedData(data: IXosFineGrainedGraphData): IXosFineGrainedGraphData {
-    data.tenants = _.filter(data.tenants, t => t.kind !== 'coarse');
-    data.networks = _.filter(data.networks, n => {
-      const subscriber = _.findIndex(data.tenants, {subscriber_network_id: n.id});
-      return subscriber > -1;
-    });
-    return data;
-  }
-
-  private graphDataToCoarseGraph(data: IXosCoarseGraphData) {
-
-    try {
-      const links: IXosServiceGraphLink[] = _.chain(data.servicedependencys)
-        .map((t: IXosTenantModel) => {
-          return {
-            id: t.id,
-            source: this.getNodeIndexById(t.provider_service_id, data.services),
-            target: this.getNodeIndexById(t.subscriber_service_id, data.services),
-            model: t
-          };
-        })
-        .value();
-
-      const nodes: IXosServiceGraphNode[] = _.map(data.services, (s: IXosServiceModel) => {
-        return {
-          id: s.id,
-          label: s.name,
-          model: s
-        };
-      });
-
-      let graph: IXosServiceGraph = {
-        nodes,
-        links
-      };
-
-      this.d3CoarseGraph.next(graph);
-    } catch (e) {
-      this.d3CoarseGraph.error(e);
-    }
-  }
-
-  private graphDataToFineGrainedGraph(data: IXosFineGrainedGraphData) {
-    try {
-      data = this.removeUnwantedFineGrainedData(data);
-
-      let nodes = _.reduce(Object.keys(data), (list: any[], k: string) => {
-        return list.concat(data[k]);
-      }, []);
-
-      nodes = _.chain(nodes)
-        .map(n => {
-          n.d3Id = this.d3Id(this.getNodeType(n), n.id);
-          return n;
-        })
-        .map(n => {
-          let node: IXosServiceGraphNode = {
-            id: n.d3Id,
-            label: this.getNodeLabel(n),
-            model: n,
-            type: this.getNodeType(n)
-          };
-          return node;
-        })
-        .value();
-
-      const links = _.reduce(data.tenants, (links: IXosServiceGraphLink[], tenant: IXosTenantModel) => {
-        const sourceId = this.getSourceId(tenant);
-        const targetId = this.getTargetId(tenant);
-        if (!angular.isDefined(targetId) || !angular.isDefined(sourceId)) {
-          // if the tenant is not pointing to anything, don't draw links
-          return links;
-        }
-
-        const tenantToProvider = {
-          id: `${sourceId}_${tenant.d3Id}`,
-          source: this.getNodeIndexById(sourceId, nodes),
-          target: this.getNodeIndexById(tenant.d3Id, nodes),
-          model: tenant
-        };
-
-        const tenantToSubscriber = {
-          id: `${tenant.d3Id}_${targetId}`,
-          source: this.getNodeIndexById(tenant.d3Id, nodes),
-          target: this.getNodeIndexById(targetId, nodes),
-          model: tenant
-        };
-
-        if (angular.isDefined(tenantToProvider.source) && angular.isDefined(tenantToProvider.target)) {
-          links.push(tenantToProvider);
-        }
-        if (angular.isDefined(tenantToSubscriber.source) && angular.isDefined(tenantToSubscriber.target)) {
-          links.push(tenantToSubscriber);
-        }
-        return links;
-      }, []);
-
-      if (nodes.length === 0 && links.length === 0) {
-        return;
-      }
-
-      let graph: IXosServiceGraph = {
-        nodes,
-        links
-      };
-
-      this.d3FineGrainedGraph.next(graph);
-    } catch (e) {
-     this.d3FineGrainedGraph.error(e);
-    }
-  }
-}
diff --git a/src/app/service-graph/services/graph.store.spec.ts b/src/app/service-graph/services/service-graph.store.spec.ts
similarity index 97%
rename from src/app/service-graph/services/graph.store.spec.ts
rename to src/app/service-graph/services/service-graph.store.spec.ts
index c083f09..7ddc393 100644
--- a/src/app/service-graph/services/graph.store.spec.ts
+++ b/src/app/service-graph/services/service-graph.store.spec.ts
@@ -1,7 +1,7 @@
 import * as angular from 'angular';
 import 'angular-mocks';
 import 'angular-ui-router';
-import {IXosServiceGraphStore, XosServiceGraphStore} from './graph.store';
+import {IXosServiceGraphStore, XosServiceGraphStore} from './service-graph.store';
 import {Subject} from 'rxjs';
 import {XosDebouncer} from '../../core/services/helpers/debounce.helper';
 import {IXosServiceGraph} from '../interfaces';
diff --git a/src/app/service-graph/services/service-graph.store.ts b/src/app/service-graph/services/service-graph.store.ts
new file mode 100644
index 0000000..d784958
--- /dev/null
+++ b/src/app/service-graph/services/service-graph.store.ts
@@ -0,0 +1,209 @@
+import * as _ from 'lodash';
+import {Observable, BehaviorSubject, Subscription} from 'rxjs';
+import {IXosModelStoreService} from '../../datasources/stores/model.store';
+import {
+  IXosServiceGraph, IXosServiceModel, IXosTenantModel, IXosCoarseGraphData,
+  IXosServiceGraphNode, IXosServiceGraphLink, IXosFineGrainedGraphData
+} from '../interfaces';
+import {IXosDebouncer} from '../../core/services/helpers/debounce.helper';
+export interface IXosServiceGraphStore {
+  // TODO remove, moved in a new service
+  get(): Observable<IXosServiceGraph>;
+  // TODO rename in get()
+  getCoarse(): Observable<IXosServiceGraph>;
+}
+
+export class XosServiceGraphStore implements IXosServiceGraphStore {
+  static $inject = [
+    '$log',
+    'XosModelStore',
+    'XosDebouncer'
+  ];
+
+  // graph data store
+  private graphData: BehaviorSubject<IXosFineGrainedGraphData> = new BehaviorSubject({
+    services: [],
+    tenants: [],
+    networks: [],
+    subscribers: [],
+    servicedependencies: []
+  });
+
+  private emptyGraph: IXosServiceGraph = {
+    nodes: [],
+    links: []
+  };
+
+  // representation of the graph as D3 requires
+  private d3CoarseGraph = new BehaviorSubject(this.emptyGraph);
+  private d3FineGrainedGraph = new BehaviorSubject(this.emptyGraph);
+
+  // storing locally reference to the data model
+  private services;
+  private tenants;
+  private subscribers;
+  private networks;
+  private servicedependencys;
+
+  // debounced functions
+  private handleData;
+
+  // datastore
+  private ServiceSubscription: Subscription;
+  private TenantSubscription: Subscription;
+  private SubscriberSubscription: Subscription;
+  private NetworkSubscription: Subscription;
+  private ServiceDependencySubscription: Subscription;
+
+  constructor (
+    private $log: ng.ILogService,
+    private XosModelStore: IXosModelStoreService,
+    private XosDebouncer: IXosDebouncer
+  ) {
+
+    this.$log.info(`[XosServiceGraphStore] Setup`);
+
+    // we want to have a quiet period of 500ms from the last event before doing anything
+    this.handleData = this.XosDebouncer.debounce(this._handleData, 500, this, false);
+
+    // observe models and populate graphData
+    this.ServiceSubscription = this.XosModelStore.query('Service', '/core/services')
+      .subscribe(
+        (res) => {
+          this.combineData(res, 'services');
+        },
+        (err) => {
+          this.$log.error(`[XosServiceGraphStore] Service Observable: `, err);
+        }
+      );
+
+    this.ServiceDependencySubscription = this.XosModelStore.query('ServiceDependency', '/core/servicedependencys')
+      .subscribe(
+        (res) => {
+          this.combineData(res, 'servicedependencies');
+        },
+        (err) => {
+          this.$log.error(`[XosServiceGraphStore] Service Observable: `, err);
+        }
+      );
+
+    this.TenantSubscription = this.XosModelStore.query('Tenant', '/core/tenants')
+      .subscribe(
+        (res) => {
+          this.combineData(res, 'tenants');
+        },
+        (err) => {
+          this.$log.error(`[XosServiceGraphStore] Tenant Observable: `, err);
+        }
+      );
+
+    this.SubscriberSubscription = this.XosModelStore.query('Tenantroot', '/core/tenantroots')
+      .subscribe(
+        (res) => {
+          this.combineData(res, 'subscribers');
+        },
+        (err) => {
+          this.$log.error(`[XosServiceGraphStore] Subscriber Observable: `, err);
+        }
+      );
+
+    this.NetworkSubscription = this.XosModelStore.query('Network', '/core/networks')
+      .subscribe(
+        (res) => {
+          this.combineData(res, 'networks');
+        },
+        (err) => {
+          this.$log.error(`[XosServiceGraphStore] graphData Observable: `, err);
+        }
+      );
+
+    // observe graphData and build Coarse and FineGrained graphs
+    this.graphData
+      .subscribe(
+        (res: IXosFineGrainedGraphData) => {
+          this.$log.debug(`[XosServiceGraphStore] New graph data received`, res);
+          this.graphDataToCoarseGraph(res);
+          // this.graphDataToFineGrainedGraph(res);
+        },
+        (err) => {
+          this.$log.error(`[XosServiceGraphStore] graphData Observable: `, err);
+        }
+      );
+  }
+
+  public get() {
+    return this.d3FineGrainedGraph.asObservable();
+  }
+
+  public getCoarse() {
+    return this.d3CoarseGraph.asObservable();
+  }
+
+  private combineData(data: any, type: 'services'|'tenants'|'subscribers'|'networks'|'servicedependencies') {
+    switch (type) {
+      case 'services':
+        this.services = data;
+        break;
+      case 'tenants':
+        this.tenants = data;
+        break;
+      case 'subscribers':
+        this.subscribers = data;
+        break;
+      case 'networks':
+        this.networks = data;
+        break;
+      case 'servicedependencies':
+        this.servicedependencys = data;
+        break;
+    }
+    this.handleData(this.services, this.tenants);
+  }
+
+  private _handleData(services: IXosServiceModel[], tenants: IXosTenantModel[]) {
+    this.graphData.next({
+      services: this.services,
+      tenants: this.tenants,
+      subscribers: this.subscribers,
+      networks: this.networks,
+      servicedependencies: this.servicedependencys
+    });
+  }
+
+  private getNodeIndexById(id: number | string, nodes: IXosServiceModel[]) {
+    return _.findIndex(nodes, {id: id});
+  }
+
+  private graphDataToCoarseGraph(data: IXosCoarseGraphData) {
+
+    try {
+      const links: IXosServiceGraphLink[] = _.chain(data.servicedependencies)
+        .map((t: IXosTenantModel) => {
+          return {
+            id: t.id,
+            source: this.getNodeIndexById(t.provider_service_id, data.services),
+            target: this.getNodeIndexById(t.subscriber_service_id, data.services),
+            model: t
+          };
+        })
+        .value();
+
+      const nodes: IXosServiceGraphNode[] = _.map(data.services, (s: IXosServiceModel) => {
+        return {
+          id: s.id,
+          label: s.name,
+          model: s
+        };
+      });
+
+      let graph: IXosServiceGraph = {
+        nodes,
+        links
+      };
+
+      this.d3CoarseGraph.next(graph);
+    } catch (e) {
+      this.d3CoarseGraph.error(e);
+    }
+  }
+}
diff --git a/src/app/service-graph/services/service-instance.graph.store.ts b/src/app/service-graph/services/service-instance.graph.store.ts
new file mode 100644
index 0000000..a6ab41e
--- /dev/null
+++ b/src/app/service-graph/services/service-instance.graph.store.ts
@@ -0,0 +1,263 @@
+import * as _ from 'lodash';
+import {Observable, BehaviorSubject, Subscription} from 'rxjs';
+import {
+  IXosServiceGraph, IXosServiceInstanceGraphData, IXosServiceGraphNode
+} from '../interfaces';
+import {IXosDebouncer} from '../../core/services/helpers/debounce.helper';
+import {IXosModelStoreService} from '../../datasources/stores/model.store';
+import {IXosServiceGraphStore} from './service-graph.store';
+
+export interface IXosServiceInstanceGraphStore {
+  get(): Observable<IXosServiceGraph>;
+}
+
+export class XosServiceInstanceGraphStore implements IXosServiceInstanceGraphStore {
+  static $inject = [
+    '$log',
+    'XosServiceGraphStore',
+    'XosModelStore',
+    'XosDebouncer'
+  ];
+
+  private CoarseGraphSubscription: Subscription;
+  private ServiceInstanceSubscription: Subscription;
+  private ServiceInstanceLinkSubscription: Subscription;
+  private NetworkSubscription: Subscription;
+
+  // debounced functions
+  private handleData;
+
+
+  // FIXME this is declared also in ServiceGraphStore
+  private emptyGraph: IXosServiceGraph = {
+    nodes: [],
+    links: []
+  };
+
+  // graph data store
+  private graphData: BehaviorSubject<IXosServiceInstanceGraphData> = new BehaviorSubject({
+    serviceGraph: this.emptyGraph,
+    serviceInstances: [],
+    serviceInstanceLinks: [],
+    networks: []
+  });
+
+  private d3ServiceInstanceGraph = new BehaviorSubject(this.emptyGraph);
+
+  private serviceGraph: IXosServiceGraph = this.emptyGraph;
+  private serviceInstances: any[] = [];
+  private serviceInstanceLinks: any[] = [];
+  private networks: any[] = [];
+
+  constructor (
+    private $log: ng.ILogService,
+    private XosServiceGraphStore: IXosServiceGraphStore,
+    private XosModelStore: IXosModelStoreService,
+    private XosDebouncer: IXosDebouncer
+  ) {
+    this.$log.info(`[XosServiceInstanceGraphStore] Setup`);
+
+    // we want to have a quiet period of 500ms from the last event before doing anything
+    this.handleData = this.XosDebouncer.debounce(this._handleData, 500, this, false);
+
+    this.CoarseGraphSubscription = this.XosServiceGraphStore.getCoarse()
+      .subscribe(
+        (graph: IXosServiceGraph) => {
+          this.combineData(graph, 'serviceGraph');
+        }
+      );
+
+    this.ServiceInstanceSubscription = this.XosModelStore.query('ServiceInstance', '/core/serviceinstances')
+      .subscribe(
+        (res) => {
+          this.combineData(res, 'serviceInstance');
+        },
+        (err) => {
+          this.$log.error(`[XosServiceInstanceGraphStore] Service Observable: `, err);
+        }
+      );
+
+    this.ServiceInstanceLinkSubscription = this.XosModelStore.query('ServiceInstanceLink', '/core/serviceinstancelinks')
+      .subscribe(
+        (res) => {
+          this.combineData(res, 'serviceInstanceLink');
+        },
+        (err) => {
+          this.$log.error(`[XosServiceInstanceGraphStore] Service Observable: `, err);
+        }
+      );
+
+    this.NetworkSubscription = this.XosModelStore.query('Network', '/core/networks')
+      .subscribe(
+        (res) => {
+          this.combineData(res, 'networks');
+        },
+        (err) => {
+          this.$log.error(`[XosServiceGraphStore] graphData Observable: `, err);
+        }
+      );
+
+    // observe graphData and build ServiceInstance graph
+    this.graphData
+      .subscribe(
+        (res: IXosServiceInstanceGraphData) => {
+          this.$log.debug(`[XosServiceInstanceGraphStore] New graph data received`, res);
+
+          this.graphDataToD3(res);
+        },
+        (err) => {
+          this.$log.error(`[XosServiceInstanceGraphStore] graphData Observable: `, err);
+        }
+      );
+  }
+
+  public get(): Observable<IXosServiceGraph> {
+    return this.d3ServiceInstanceGraph;
+  }
+
+  // called by all the observables, combine the data in a globla graph observable
+  private combineData(data: any, type: 'serviceGraph' | 'serviceInstance' | 'serviceInstanceLink' | 'serviceInterface' | 'networks') {
+    switch (type) {
+      case 'serviceGraph':
+        this.serviceGraph = angular.copy(data);
+        break;
+      case 'serviceInstance':
+        this.serviceInstances = data;
+        break;
+      case 'serviceInstanceLink':
+        this.serviceInstanceLinks = data;
+        break;
+      case 'networks':
+        this.networks = data;
+        break;
+    }
+    this.handleData();
+  }
+
+  private _handleData() {
+    this.graphData.next({
+      serviceGraph: this.serviceGraph,
+      serviceInstances: this.serviceInstances,
+      serviceInstanceLinks: this.serviceInstanceLinks,
+      networks: this.networks
+    });
+  }
+
+  private getNodeType(n: any) {
+    return n.class_names.split(',')[0].toLowerCase();
+  }
+
+  private getNodeLabel(n: any) {
+    if (this.getNodeType(n) === 'serviceinstance') {
+      return n.name ? n.name : n.id;
+    }
+    return n.humanReadableName ? n.humanReadableName : n.name;
+  }
+
+  private d3Id(type: string, id: number) {
+    return `${type.toLowerCase()}~${id}`;
+  }
+
+  private toD3Node(n: any): IXosServiceGraphNode {
+    return {
+      id: this.d3Id(this.getNodeType(n), n.id),
+      label: this.getNodeLabel(n),
+      model: n,
+      type: this.getNodeType(n)
+    };
+  }
+
+  private getServiceInstanceIndexById(l: any, nodes: any[], where: 'source' | 'target'): string {
+    if (where === 'source') {
+      return _.find(nodes, {id: `serviceinstance~${l.provider_service_instance_id}`});
+    }
+    else {
+      if (l.subscriber_service_id) {
+        return _.find(nodes, {id: `service~${l.subscriber_service_id}`});
+      }
+      else if (l.subscriber_network_id) {
+        return _.find(nodes, {id: `network~${l.subscriber_network_id}`});
+      }
+      else if (l.subscriber_service_instance_id) {
+        return _.find(nodes, {id: `serviceinstance~${l.subscriber_service_instance_id}`});
+      }
+    }
+  }
+
+  private getOwnerById(id: number, nodes: any[]): any {
+    return _.find(nodes, {id: `service~${id}`});
+  }
+
+  private graphDataToD3(data: IXosServiceInstanceGraphData) {
+    try {
+      // get all the nodes
+      let nodes = _.chain(data.serviceGraph.nodes)
+        .map(n => {
+          // HACK we are receiving node as d3 models
+          return n.model;
+        })
+        .map(n => {
+          return this.toD3Node(n);
+        })
+        .value();
+
+      data.serviceInstances = _.chain(data.serviceInstances)
+        .map(n => {
+          return this.toD3Node(n);
+        })
+        .value();
+      nodes = nodes.concat(data.serviceInstances);
+
+      data.networks = _.chain(data.networks)
+        .filter(n => {
+          const subscriber = _.findIndex(data.serviceInstanceLinks, {subscriber_network_id: n.id});
+          return subscriber > -1;
+        })
+        .map(n => {
+          return this.toD3Node(n);
+        })
+        .value();
+      nodes = nodes.concat(data.networks);
+
+      let links = data.serviceGraph.links;
+
+      // create the links starting from the coarse ones
+      links = _.reduce(data.serviceInstanceLinks, (links, l) => {
+        let link =  {
+          id: `service_instance_link~${l.id}`,
+          source: this.getServiceInstanceIndexById(l, nodes, 'source'),
+          target: this.getServiceInstanceIndexById(l, nodes, 'target'),
+          model: l,
+          d3Class: 'service-instance'
+        };
+        links.push(link);
+        return links;
+      }, data.serviceGraph.links);
+
+      const linksToService = _.reduce(data.serviceInstances, (links, n) => {
+        if (angular.isDefined(n.model.owner_id)) {
+          let link =  {
+            id: `owner~${n.id}`,
+            source: n,
+            target: this.getOwnerById(n.model.owner_id, nodes),
+            model: n,
+            d3Class: 'owner'
+          };
+          links.push(link);
+        }
+        return links;
+      }, []);
+
+      links = links.concat(linksToService);
+
+      let graph: IXosServiceGraph = {
+        nodes,
+        links
+      };
+
+      this.d3ServiceInstanceGraph.next(graph);
+    } catch (e) {
+      this.d3ServiceInstanceGraph.error(e);
+    }
+  }
+}