Enabling Code Formatter
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / services / workflow-service / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / services / workflow / ImperativeWorkflowExecutionService.kt
1 /*
2  *  Copyright © 2019 IBM.
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  */
16
17 package org.onap.ccsdk.cds.blueprintsprocessor.services.workflow
18
19 import kotlinx.coroutines.CompletableDeferred
20 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
21 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceOutput
22 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.Status
23 import org.onap.ccsdk.cds.controllerblueprints.common.api.EventType
24 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
25 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
26 import org.onap.ccsdk.cds.controllerblueprints.core.asGraph
27 import org.onap.ccsdk.cds.controllerblueprints.core.checkNotEmpty
28 import org.onap.ccsdk.cds.controllerblueprints.core.data.EdgeLabel
29 import org.onap.ccsdk.cds.controllerblueprints.core.data.Graph
30 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintWorkflowExecutionService
31 import org.onap.ccsdk.cds.controllerblueprints.core.logger
32 import org.onap.ccsdk.cds.controllerblueprints.core.service.AbstractBluePrintWorkFlowService
33 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService
34 import org.onap.ccsdk.cds.controllerblueprints.core.service.NodeExecuteMessage
35 import org.onap.ccsdk.cds.controllerblueprints.core.service.NodeSkipMessage
36 import org.onap.ccsdk.cds.controllerblueprints.core.service.WorkflowExecuteMessage
37 import org.springframework.stereotype.Service
38
39 @Service("imperativeWorkflowExecutionService")
40 class ImperativeWorkflowExecutionService(
41     private val nodeTemplateExecutionService: NodeTemplateExecutionService
42 ) :
43     BluePrintWorkflowExecutionService<ExecutionServiceInput, ExecutionServiceOutput> {
44
45     override suspend fun executeBluePrintWorkflow(
46         bluePrintRuntimeService: BluePrintRuntimeService<*>,
47         executionServiceInput: ExecutionServiceInput,
48         properties: MutableMap<String, Any>
49     ): ExecutionServiceOutput {
50
51         val bluePrintContext = bluePrintRuntimeService.bluePrintContext()
52
53         val workflowName = executionServiceInput.actionIdentifiers.actionName
54
55         val graph = bluePrintContext.workflowByName(workflowName).asGraph()
56
57         return ImperativeBluePrintWorkflowService(nodeTemplateExecutionService)
58             .executeWorkflow(graph, bluePrintRuntimeService, executionServiceInput)
59     }
60 }
61
62 open class ImperativeBluePrintWorkflowService(private val nodeTemplateExecutionService: NodeTemplateExecutionService) :
63     AbstractBluePrintWorkFlowService<ExecutionServiceInput, ExecutionServiceOutput>() {
64
65     val log = logger(ImperativeBluePrintWorkflowService::class)
66
67     lateinit var bluePrintRuntimeService: BluePrintRuntimeService<*>
68     lateinit var executionServiceInput: ExecutionServiceInput
69     lateinit var workflowName: String
70
71     override suspend fun executeWorkflow(
72         graph: Graph,
73         bluePrintRuntimeService: BluePrintRuntimeService<*>,
74         input: ExecutionServiceInput
75     ): ExecutionServiceOutput {
76         this.graph = graph
77         this.bluePrintRuntimeService = bluePrintRuntimeService
78         this.executionServiceInput = input
79         this.workflowName = this.executionServiceInput.actionIdentifiers.actionName
80         this.workflowId = bluePrintRuntimeService.id()
81         val output = CompletableDeferred<ExecutionServiceOutput>()
82         val startMessage = WorkflowExecuteMessage(input, output)
83         val workflowActor = workflowActor()
84         if (!workflowActor.isClosedForSend) {
85             workflowActor.send(startMessage)
86         } else {
87             throw BluePrintProcessorException("workflow($workflowActor) actor is closed")
88         }
89         return output.await()
90     }
91
92     override suspend fun initializeWorkflow(input: ExecutionServiceInput): EdgeLabel {
93         return EdgeLabel.SUCCESS
94     }
95
96     override suspend fun prepareWorkflowOutput(): ExecutionServiceOutput {
97         val wfStatus = Status().apply {
98             if (exceptions.isNotEmpty()) {
99                 exceptions.forEach {
100                     val errorMessage = it.message ?: ""
101                     bluePrintRuntimeService.getBluePrintError().addError(errorMessage)
102                     log.error("workflow($workflowId) exception :", it)
103                 }
104                 message = BluePrintConstants.STATUS_FAILURE
105             } else {
106                 message = BluePrintConstants.STATUS_SUCCESS
107             }
108             eventType = EventType.EVENT_COMPONENT_EXECUTED.name
109         }
110         return ExecutionServiceOutput().apply {
111             commonHeader = executionServiceInput.commonHeader
112             actionIdentifiers = executionServiceInput.actionIdentifiers
113             status = wfStatus
114         }
115     }
116
117     override suspend fun prepareNodeExecutionMessage(node: Graph.Node):
118         NodeExecuteMessage<ExecutionServiceInput, ExecutionServiceOutput> {
119             val nodeOutput = ExecutionServiceOutput().apply {
120                 commonHeader = executionServiceInput.commonHeader
121                 actionIdentifiers = executionServiceInput.actionIdentifiers
122             }
123             return NodeExecuteMessage(node, executionServiceInput, nodeOutput)
124         }
125
126     override suspend fun prepareNodeSkipMessage(node: Graph.Node):
127         NodeSkipMessage<ExecutionServiceInput, ExecutionServiceOutput> {
128             val nodeOutput = ExecutionServiceOutput().apply {
129                 commonHeader = executionServiceInput.commonHeader
130                 actionIdentifiers = executionServiceInput.actionIdentifiers
131             }
132             return NodeSkipMessage(node, executionServiceInput, nodeOutput)
133         }
134
135     override suspend fun executeNode(
136         node: Graph.Node,
137         nodeInput: ExecutionServiceInput,
138         nodeOutput: ExecutionServiceOutput
139     ): EdgeLabel {
140         log.info("Executing workflow($workflowName[${this.workflowId}])'s step(${node.id})")
141         val step = bluePrintRuntimeService.bluePrintContext().workflowStepByName(this.workflowName, node.id)
142         checkNotEmpty(step.target) { "couldn't get step target for workflow(${this.workflowName})'s step(${node.id})" }
143         val nodeTemplateName = step.target!!
144
145         /** execute node template */
146         val executionServiceOutput = nodeTemplateExecutionService
147             .executeNodeTemplate(bluePrintRuntimeService, nodeTemplateName, nodeInput)
148
149         return when (executionServiceOutput.status.message) {
150             BluePrintConstants.STATUS_FAILURE -> EdgeLabel.FAILURE
151             else -> EdgeLabel.SUCCESS
152         }
153     }
154
155     override suspend fun skipNode(
156         node: Graph.Node,
157         nodeInput: ExecutionServiceInput,
158         nodeOutput: ExecutionServiceOutput
159     ): EdgeLabel {
160         return EdgeLabel.SUCCESS
161     }
162
163     override suspend fun cancelNode(
164         node: Graph.Node,
165         nodeInput: ExecutionServiceInput,
166         nodeOutput: ExecutionServiceOutput
167     ): EdgeLabel {
168         TODO("not implemented")
169     }
170
171     override suspend fun restartNode(
172         node: Graph.Node,
173         nodeInput: ExecutionServiceInput,
174         nodeOutput: ExecutionServiceOutput
175     ): EdgeLabel {
176         TODO("not implemented")
177     }
178 }