support quote output of rest task

rest task's parameters can quote output parameter of previous rest tasks.

Issue-ID: SDC-121

Change-Id: I94f2058f7b8b2ad600ffb99c8838b37da5bb5b9d
Signed-off-by: Lvbo163 <lv.bo163@zte.com.cn>
diff --git a/sdc-workflow-designer-ui/src/app/app.module.ts b/sdc-workflow-designer-ui/src/app/app.module.ts
index 0bf4b14..047f468 100644
--- a/sdc-workflow-designer-ui/src/app/app.module.ts
+++ b/sdc-workflow-designer-ui/src/app/app.module.ts
@@ -42,6 +42,7 @@
 import { ParameterTreeComponent } from "./components/parameter-tree/parameter-tree.component";
 import { EditablePropertyComponent } from "./components/editable-property/editable-property.component";
 import { SwaggerTreeConverterService } from "./services/swagger-tree-converter.service";
+import { WorkflowProcessService } from "./services/workflow-process.service";
 
 @NgModule({
     declarations: [
@@ -85,6 +86,7 @@
         JsPlumbService,
         SwaggerTreeConverterService,
         WorkflowConfigService,
+        WorkflowProcessService,
         WorkflowService
     ],
     bootstrap: [AppComponent]
diff --git a/sdc-workflow-designer-ui/src/app/components/parameter-tree/parameter-tree.component.ts b/sdc-workflow-designer-ui/src/app/components/parameter-tree/parameter-tree.component.ts
index d0e04e3..0de35b9 100644
--- a/sdc-workflow-designer-ui/src/app/components/parameter-tree/parameter-tree.component.ts
+++ b/sdc-workflow-designer-ui/src/app/components/parameter-tree/parameter-tree.component.ts
@@ -186,7 +186,6 @@
     }
 
     private formatParam(params: any[]): void {
-        console.log(params);
         params.forEach(param => this.initParam(param));
     }
 
diff --git a/sdc-workflow-designer-ui/src/app/components/parameter/parameter.component.ts b/sdc-workflow-designer-ui/src/app/components/parameter/parameter.component.ts
index 2cd5a0f..3539c8f 100644
--- a/sdc-workflow-designer-ui/src/app/components/parameter/parameter.component.ts
+++ b/sdc-workflow-designer-ui/src/app/components/parameter/parameter.component.ts
@@ -45,7 +45,6 @@
     constructor(private dataAccessService: DataAccessService) { }

 

     public ngOnInit(): void {

-        console.log(this.planItems);

         if (1 === this.valueSource.length) {

             this.showValueSource = false;

         }

diff --git a/sdc-workflow-designer-ui/src/app/components/property/properties.component.ts b/sdc-workflow-designer-ui/src/app/components/property/properties.component.ts
index f3f784a..2aa552e 100644
--- a/sdc-workflow-designer-ui/src/app/components/property/properties.component.ts
+++ b/sdc-workflow-designer-ui/src/app/components/property/properties.component.ts
@@ -15,8 +15,8 @@
 import { WorkflowNode } from '../../model/workflow/workflow-node';
 import { BroadcastService } from '../../services/broadcast.service';
 import { JsPlumbService } from '../../services/jsplumb.service';
-import { WorkflowService } from '../../services/workflow.service';
 import { PlanTreeviewItem } from "../../model/plan-treeview-item";
+import { WorkflowProcessService } from "../../services/workflow-process.service";
 
 /**
  * property component presents information of a workflow node.
@@ -36,7 +36,7 @@
 
     constructor(private broadcastService: BroadcastService,
                 private jsPlumnService: JsPlumbService,
-                private workflowService: WorkflowService) {
+                private processService: WorkflowProcessService) {
 
     }
 
@@ -44,7 +44,7 @@
         this.broadcastService.showProperty$.subscribe(show => this.show = show);
         this.broadcastService.nodeProperty$.subscribe(node => {
             this.node = node;
-            this.planItems = this.workflowService.getPlanParameters(this.node.id);
+            this.planItems = this.processService.getPlanParameters(this.node.id);
         });
     }
 
@@ -57,6 +57,6 @@
         this.show = false;
 
         this.jsPlumnService.remove(this.node.id);
-        this.workflowService.deleteNode(this.node.id);
+        this.processService.deleteNode(this.node.id);
     }
 }
diff --git a/sdc-workflow-designer-ui/src/app/services/jsplumb.service.ts b/sdc-workflow-designer-ui/src/app/services/jsplumb.service.ts
index ffd00c6..543b09f 100644
--- a/sdc-workflow-designer-ui/src/app/services/jsplumb.service.ts
+++ b/sdc-workflow-designer-ui/src/app/services/jsplumb.service.ts
@@ -12,7 +12,7 @@
 

 import { Injectable } from '@angular/core';

 import * as jsp from 'jsplumb';

-import { WorkflowService } from "./workflow.service";

+import { WorkflowProcessService } from "./workflow-process.service";

 

 /**

  * JsPlumbService

@@ -22,7 +22,7 @@
 export class JsPlumbService {

     public jsplumbInstance;

 

-    constructor(private workflowService: WorkflowService) {

+    constructor(private processService: WorkflowProcessService) {

         this.initJsPlumbInstance();

     }

 

@@ -58,11 +58,11 @@
 

         // add connection to model data while a new connection is build

         this.jsplumbInstance.bind('connection', info => {

-            this.workflowService.addSequenceFlow(info.connection.sourceId, info.connection.targetId);

+            this.processService.addSequenceFlow(info.connection.sourceId, info.connection.targetId);

 

             info.connection.bind('click', connection => {

                 this.jsplumbInstance.select({ connections: [connection] }).delete();

-                this.workflowService.deleteSequenceFlow(connection.sourceId, connection.targetId);

+                this.processService.deleteSequenceFlow(connection.sourceId, connection.targetId);

             });

         });

 

@@ -117,7 +117,7 @@
                 const left = event.e.clientX - 220 - (event.e.offsetX / 2);

                 const top = event.e.clientY - 70 - (event.e.offsetY / 2);

 

-                this.workflowService.addNode(type, type, top, left);

+                this.processService.addNode(type, type, top, left);

             },

         });

     }

diff --git a/sdc-workflow-designer-ui/src/app/services/workflow-process.service.ts b/sdc-workflow-designer-ui/src/app/services/workflow-process.service.ts
new file mode 100644
index 0000000..4c701ec
--- /dev/null
+++ b/sdc-workflow-designer-ui/src/app/services/workflow-process.service.ts
@@ -0,0 +1,206 @@
+/**

+ * Copyright (c) 2017 ZTE Corporation.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and the Apache License 2.0 which both accompany this distribution,

+ * and are available at http://www.eclipse.org/legal/epl-v10.html

+ * and http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Contributors:

+ *     ZTE - initial API and implementation and/or initial documentation

+ */

+

+import { Injectable } from '@angular/core';

+import { WorkflowNode } from "../model/workflow/workflow-node";

+import { Workflow } from "../model/workflow/workflow";

+import { Position } from "../model/workflow/position";

+import { NodeType } from "../model/workflow/node-type.enum";

+import { StartEvent } from "../model/workflow/start-event";

+import { SequenceFlow } from "../model/workflow/sequence-flow";

+import { RestTask } from "../model/workflow/rest-task";

+import { PlanTreeviewItem } from "../model/plan-treeview-item";

+import { WorkflowConfigService } from "./workflow-config.service";

+import { Swagger, SwaggerModelSimple, SwaggerReferenceObject } from "../model/swagger";

+import { WorkflowService } from "./workflow.service";

+

+/**

+ * WorkflowService

+ * provides all of the operations about workflow operations.

+ */

+@Injectable()

+export class WorkflowProcessService {

+

+    constructor(private workflowService: WorkflowService, private configService: WorkflowConfigService) {

+

+    }

+

+    public getProcess(): WorkflowNode[] {

+        return this.workflowService.workflow.nodes;

+    }

+

+    public addNode(name: string, type: string, top: number, left: number): WorkflowNode {

+        let node: WorkflowNode;

+        switch (type) {

+            case NodeType[NodeType.startEvent]:

+                node = new StartEvent(this.createId(), name, type, new Position(top, left), []);

+                break;

+            case NodeType[NodeType.restTask]:

+                node = new RestTask(this.createId(), name, type, new Position(top, left), []);

+                break;

+            default:

+                node = new WorkflowNode(this.createId(), name, type, new Position(top, left), []);

+                break;

+        }

+

+        this.getProcess().push(node);

+        return node;

+    }

+

+    public deleteNode(nodeId: string): WorkflowNode {

+        // delete related connections

+        this.getProcess().forEach(node => this.deleteSequenceFlow(node.id, nodeId));

+

+        // delete current node

+        const index = this.getProcess().findIndex(node => node.id === nodeId);

+        if (index !== -1) {

+            const node = this.getProcess().splice(index, 1)[0];

+            node.sequenceFlows = [];

+            return node;

+        }

+

+        return undefined;

+    }

+

+    public addSequenceFlow(sourceId: string, targetId: string) {

+        const node = this.getNodeById(sourceId);

+        if (node) {

+            const index = node.sequenceFlows.findIndex(sequenceFlow => sequenceFlow.targetRef === targetId);

+            if (index === -1) {

+                node.sequenceFlows.push(new SequenceFlow(sourceId, targetId));

+            }

+        }

+    }

+

+    public deleteSequenceFlow(sourceId: string, targetId: string) {

+        const node = this.getNodeById(sourceId);

+        if (node) {

+            const index = node.sequenceFlows.findIndex(sequenceFlow => sequenceFlow.targetRef === targetId);

+            if (index !== -1) {

+                node.sequenceFlows.splice(index, 1);

+            }

+        }

+    }

+

+    public getPlanParameters(nodeId: string): PlanTreeviewItem[] {

+        const preNodeList = new Array<WorkflowNode>();

+        this.getPreNodes(nodeId, preNodeList);

+

+        return this.loadNodeOutputs(preNodeList);

+    }

+

+    private loadNodeOutputs(nodes: WorkflowNode[]): PlanTreeviewItem[] {

+        const params = new Array<PlanTreeviewItem>();

+        nodes.forEach(node => {

+            switch (node.type) {

+                case NodeType[NodeType.startEvent]:

+                    params.push(this.loadOutput4StartEvent(<StartEvent>node));

+                    break;

+                case NodeType[NodeType.restTask]:

+                    params.push(this.loadOutput4RestTask(<RestTask>node));

+                    break;

+                default:

+                    break;

+            }

+        });

+

+        return params;

+    }

+

+    private loadOutput4StartEvent(node: StartEvent): PlanTreeviewItem {

+        const startItem = new PlanTreeviewItem(node.name, `[${node.id}]`, []);

+        node.parameters.map(param =>

+            startItem.children.push(new PlanTreeviewItem(param.name, `[${param.name}]`, [])));

+        return startItem;

+    }

+

+    private loadOutput4RestTask(node: RestTask): PlanTreeviewItem {

+        const item = new PlanTreeviewItem(node.name, `[${node.id}]`, []);

+        item.children.push(this.createStatusCodeTreeViewItem(node.id));

+

+        if (node.responses.length !== 0) { // load rest responses

+            const responseItem = this.createResponseTreeViewItem(node.id);

+            item.children.push(responseItem);

+            if (node.responses[0]) {

+                const swagger = this.configService.getSwaggerInfo(node.serviceName, node.serviceVersion);

+                const swaggerDefinition = this.configService.getDefinition(swagger, node.responses[0].schema.$ref);

+                this.loadParamsBySwaggerDefinition(responseItem, swagger, <SwaggerModelSimple>swaggerDefinition);

+            }

+        }

+

+        return item;

+    }

+

+    private createStatusCodeTreeViewItem(nodeId: string): PlanTreeviewItem {

+        return new PlanTreeviewItem('statusCode', `[${nodeId}].[statusCode]`, []);

+    }

+

+    private createResponseTreeViewItem(nodeId: string): PlanTreeviewItem {

+        return new PlanTreeviewItem('response', `[${nodeId}].[responseBody]`, []);

+    }

+

+    private loadParamsBySwaggerDefinition(parentItem: PlanTreeviewItem, swagger: Swagger, definition: SwaggerModelSimple) {

+        Object.getOwnPropertyNames(definition.properties).map(key => {

+            const property = definition.properties[key];

+            const value = `${parentItem.value}.[${key}]`;

+            const propertyItem = new PlanTreeviewItem(key, value, []);

+            parentItem.children.push(propertyItem);

+

+            if (property instanceof SwaggerReferenceObject) {

+                const propertyDefinition = this.configService.getDefinition(swagger, property.$ref);

+                this.loadParamsBySwaggerDefinition(propertyItem, swagger,

+                    <SwaggerModelSimple>propertyDefinition);

+            }

+

+            return propertyItem;

+        });

+    }

+

+    public getPreNodes(nodeId: string, preNodes: WorkflowNode[]) {

+        const preNode4CurrentNode = [];

+        this.getProcess().forEach(node => {

+            if (this.isPreNode(node, nodeId)) {

+                const existNode = preNodes.find(tmpNode => tmpNode.id === node.id);

+                if (existNode) {

+                    // current node already exists in preNodes. this could avoid loop circle.

+                } else {

+                    preNode4CurrentNode.push(node);

+                    preNodes.push(node);

+                }

+            }

+        });

+

+        preNode4CurrentNode.forEach(node => this.getPreNodes(node.id, preNodes));

+    }

+

+    public isPreNode(preNode: WorkflowNode, id: string): boolean {

+        const targetNode = preNode.sequenceFlows.find(connection => connection.targetRef === id);

+        return targetNode !== undefined;

+    }

+

+    public getNodeById(sourceId: string): WorkflowNode {

+        return this.getProcess().find(node => node.id === sourceId);

+    }

+

+    private createId() {

+        const idSet = new Set();

+        this.getProcess().forEach(node => idSet.add(node.id));

+

+        for (let i = 0; i < idSet.size; i++) {

+            if (!idSet.has('node' + i)) {

+                return 'node' + i;

+            }

+        }

+

+        return 'node' + idSet.size;

+    }

+}

diff --git a/sdc-workflow-designer-ui/src/app/services/workflow.service.ts b/sdc-workflow-designer-ui/src/app/services/workflow.service.ts
index 4bcd43b..7d75192 100644
--- a/sdc-workflow-designer-ui/src/app/services/workflow.service.ts
+++ b/sdc-workflow-designer-ui/src/app/services/workflow.service.ts
@@ -11,16 +11,9 @@
  */

 

 import { Injectable } from '@angular/core';

-import { WorkflowNode } from "../model/workflow/workflow-node";

 import { DataAccessService } from "./data-access/data-access.service";

 import { Observable } from "rxjs/Observable";

 import { Workflow } from "../model/workflow/workflow";

-import { Position } from "../model/workflow/position";

-import { NodeType } from "../model/workflow/node-type.enum";

-import { StartEvent } from "../model/workflow/start-event";

-import { SequenceFlow } from "../model/workflow/sequence-flow";

-import { RestTask } from "../model/workflow/rest-task";

-import { PlanTreeviewItem } from "../model/plan-treeview-item";

 

 /**

  * WorkflowService

@@ -39,128 +32,4 @@
         console.log(this.workflow);

         return this.dataAccessService.catalogService.saveWorkflow(this.workflow);

     }

-

-    public addNode(name: string, type: string, top: number, left: number): WorkflowNode {

-        let node: WorkflowNode;

-        switch (type) {

-            case NodeType[NodeType.startEvent]:

-                node = new StartEvent(this.createId(), name, type, new Position(top, left), []);

-                break;

-            case NodeType[NodeType.restTask]:

-                node = new RestTask(this.createId(), name, type, new Position(top, left), []);

-                break;

-            default:

-                node = new WorkflowNode(this.createId(), name, type, new Position(top, left), []);

-                break;

-        }

-

-        this.workflow.nodes.push(node);

-        return node;

-    }

-

-    public deleteNode(nodeId: string): WorkflowNode {

-        // delete related connections

-        this.workflow.nodes.forEach(node => this.deleteSequenceFlow(node.id, nodeId));

-

-        // delete current node

-        const index = this.workflow.nodes.findIndex(node => node.id === nodeId);

-        if (index !== -1) {

-            const node = this.workflow.nodes.splice(index, 1)[0];

-            node.sequenceFlows = [];

-            return node;

-        }

-

-        return undefined;

-    }

-

-    public addSequenceFlow(sourceId: string, targetId: string) {

-        const node = this.getNodeById(sourceId);

-        if (node) {

-            const index = node.sequenceFlows.findIndex(sequenceFlow => sequenceFlow.targetRef === targetId);

-            if (index === -1) {

-                node.sequenceFlows.push(new SequenceFlow(sourceId, targetId));

-            }

-        }

-    }

-

-    public deleteSequenceFlow(sourceId: string, targetId: string) {

-        const node = this.getNodeById(sourceId);

-        if (node) {

-            const index = node.sequenceFlows.findIndex(sequenceFlow => sequenceFlow.targetRef === targetId);

-            if (index !== -1) {

-                node.sequenceFlows.splice(index, 1);

-            }

-        }

-    }

-

-    public getPlanParameters(nodeId: string): PlanTreeviewItem[] {

-        const preNodeList = new Array<WorkflowNode>();

-        this.getPreNodes(nodeId, preNodeList);

-

-        return this.loadNodeOutputs(preNodeList);

-    }

-

-    private loadNodeOutputs(nodes: WorkflowNode[]): PlanTreeviewItem[] {

-        const params = new Array<PlanTreeviewItem>();

-        nodes.forEach(node => {

-            switch (node.type) {

-                case NodeType[NodeType.startEvent]:

-                    params.push(this.loadOutput4StartEvent(<StartEvent>node));

-                    break;

-                case NodeType[NodeType.restTask]:

-                    // TODO for rest task

-                    break;

-                default:

-                    break;

-            }

-        });

-

-        return params;

-    }

-

-    private loadOutput4StartEvent(node: StartEvent): PlanTreeviewItem {

-        const startItem = new PlanTreeviewItem(node.name, `[${node.id}]`, []);

-        node.parameters.map(param =>

-            startItem.children.push(new PlanTreeviewItem(param.name, `[${param.name}]`, [])));

-        return startItem;

-    }

-

-    public getPreNodes(nodeId: string, preNodes: WorkflowNode[]) {

-        const preNode4CurrentNode = [];

-        this.workflow.nodes.forEach(node => {

-            if (this.isPreNode(node, nodeId)) {

-                const existNode = preNodes.find(tmpNode => tmpNode.id === node.id);

-                if (existNode) {

-                    // current node already exists in preNodes. this could avoid loop circle.

-                } else {

-                    preNode4CurrentNode.push(node);

-                    preNodes.push(node);

-                }

-            }

-        });

-

-        preNode4CurrentNode.forEach(node => this.getPreNodes(node.id, preNodes));

-    }

-

-    public isPreNode(preNode: WorkflowNode, id: string): boolean {

-        const targetNode = preNode.sequenceFlows.find(connection => connection.targetRef === id);

-        return targetNode !== undefined;

-    }

-

-    public getNodeById(sourceId: string): WorkflowNode {

-        return this.workflow.nodes.find(node => node.id === sourceId);

-    }

-

-    private createId() {

-        const idSet = new Set();

-        this.workflow.nodes.forEach(node => idSet.add(node.id));

-

-        for (let i = 0; i < idSet.size; i++) {

-            if (!idSet.has('node' + i)) {

-                return 'node' + i;

-            }

-        }

-

-        return 'node' + idSet.size;

-    }

 }