Renaming Files having BluePrint to have Blueprint
[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 kotlinx.coroutines.coroutineScope
21 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
22 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceOutput
23 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.Status
24 import org.onap.ccsdk.cds.controllerblueprints.common.api.EventType
25 import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintConstants
26 import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintProcessorException
27 import org.onap.ccsdk.cds.controllerblueprints.core.MDCContext
28 import org.onap.ccsdk.cds.controllerblueprints.core.asGraph
29 import org.onap.ccsdk.cds.controllerblueprints.core.checkNotEmpty
30 import org.onap.ccsdk.cds.controllerblueprints.core.data.EdgeLabel
31 import org.onap.ccsdk.cds.controllerblueprints.core.data.Graph
32 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BlueprintWorkflowExecutionService
33 import org.onap.ccsdk.cds.controllerblueprints.core.logger
34 import org.onap.ccsdk.cds.controllerblueprints.core.service.AbstractBlueprintWorkFlowService
35 import org.onap.ccsdk.cds.controllerblueprints.core.service.BlueprintRuntimeService
36 import org.onap.ccsdk.cds.controllerblueprints.core.service.NodeExecuteMessage
37 import org.onap.ccsdk.cds.controllerblueprints.core.service.NodeSkipMessage
38 import org.onap.ccsdk.cds.controllerblueprints.core.service.WorkflowExecuteMessage
39 import org.springframework.stereotype.Service
40 import kotlin.coroutines.CoroutineContext
41
42 @Service("imperativeWorkflowExecutionService")
43 class ImperativeWorkflowExecutionService(
44     private val nodeTemplateExecutionService: NodeTemplateExecutionService
45 ) :
46     BlueprintWorkflowExecutionService<ExecutionServiceInput, ExecutionServiceOutput> {
47
48     override suspend fun executeBlueprintWorkflow(
49         bluePrintRuntimeService: BlueprintRuntimeService<*>,
50         executionServiceInput: ExecutionServiceInput,
51         properties: MutableMap<String, Any>
52     ): ExecutionServiceOutput {
53
54         val bluePrintContext = bluePrintRuntimeService.bluePrintContext()
55
56         val workflowName = executionServiceInput.actionIdentifiers.actionName
57
58         val graph = bluePrintContext.workflowByName(workflowName).asGraph()
59
60         return coroutineScope {
61             ImperativeBlueprintWorkflowService(
62                 nodeTemplateExecutionService,
63                 this.coroutineContext[MDCContext]
64             )
65         }.let { it.executeWorkflow(graph, bluePrintRuntimeService, executionServiceInput) }
66     }
67 }
68
69 open class ImperativeBlueprintWorkflowService(private val nodeTemplateExecutionService: NodeTemplateExecutionService, private val mdcContext: CoroutineContext?) :
70     AbstractBlueprintWorkFlowService<ExecutionServiceInput, ExecutionServiceOutput>() {
71
72     final override val coroutineContext: CoroutineContext
73         get() = mdcContext?.let { super.coroutineContext + it } ?: super.coroutineContext
74
75     val log = logger(ImperativeBlueprintWorkflowService::class)
76
77     lateinit var bluePrintRuntimeService: BlueprintRuntimeService<*>
78     lateinit var executionServiceInput: ExecutionServiceInput
79     lateinit var workflowName: String
80
81     override suspend fun executeWorkflow(
82         graph: Graph,
83         bluePrintRuntimeService: BlueprintRuntimeService<*>,
84         input: ExecutionServiceInput
85     ): ExecutionServiceOutput {
86         this.graph = graph
87         this.bluePrintRuntimeService = bluePrintRuntimeService
88         this.executionServiceInput = input
89         this.workflowName = this.executionServiceInput.actionIdentifiers.actionName
90         this.workflowId = bluePrintRuntimeService.id()
91         val output = CompletableDeferred<ExecutionServiceOutput>()
92         val startMessage = WorkflowExecuteMessage(input, output)
93         val workflowActor = workflowActor()
94         if (!workflowActor.isClosedForSend) {
95             workflowActor.send(startMessage)
96         } else {
97             throw BlueprintProcessorException("workflow($workflowActor) actor is closed")
98         }
99         return output.await()
100     }
101
102     override suspend fun initializeWorkflow(input: ExecutionServiceInput): EdgeLabel {
103         return EdgeLabel.SUCCESS
104     }
105
106     override suspend fun prepareWorkflowOutput(): ExecutionServiceOutput {
107         val wfStatus = Status().apply {
108             if (exceptions.isNotEmpty()) {
109                 exceptions.forEach {
110                     val errorMessage = it.message ?: ""
111                     bluePrintRuntimeService.getBlueprintError().addError(errorMessage)
112                     log.error("workflow($workflowId) exception :", it)
113                 }
114                 message = BlueprintConstants.STATUS_FAILURE
115             } else {
116                 message = BlueprintConstants.STATUS_SUCCESS
117             }
118             eventType = EventType.EVENT_COMPONENT_EXECUTED.name
119         }
120         return ExecutionServiceOutput().apply {
121             commonHeader = executionServiceInput.commonHeader
122             actionIdentifiers = executionServiceInput.actionIdentifiers
123             status = wfStatus
124         }
125     }
126
127     override suspend fun prepareNodeExecutionMessage(node: Graph.Node):
128         NodeExecuteMessage<ExecutionServiceInput, ExecutionServiceOutput> {
129             val nodeOutput = ExecutionServiceOutput().apply {
130                 commonHeader = executionServiceInput.commonHeader
131                 actionIdentifiers = executionServiceInput.actionIdentifiers
132             }
133             return NodeExecuteMessage(node, executionServiceInput, nodeOutput)
134         }
135
136     override suspend fun prepareNodeSkipMessage(node: Graph.Node):
137         NodeSkipMessage<ExecutionServiceInput, ExecutionServiceOutput> {
138             val nodeOutput = ExecutionServiceOutput().apply {
139                 commonHeader = executionServiceInput.commonHeader
140                 actionIdentifiers = executionServiceInput.actionIdentifiers
141             }
142             return NodeSkipMessage(node, executionServiceInput, nodeOutput)
143         }
144
145     override suspend fun executeNode(
146         node: Graph.Node,
147         nodeInput: ExecutionServiceInput,
148         nodeOutput: ExecutionServiceOutput
149     ): EdgeLabel {
150         log.info("Executing workflow($workflowName[${this.workflowId}])'s step(${node.id})")
151         val step = bluePrintRuntimeService.bluePrintContext().workflowStepByName(this.workflowName, node.id)
152         checkNotEmpty(step.target) { "couldn't get step target for workflow(${this.workflowName})'s step(${node.id})" }
153         val nodeTemplateName = step.target!!
154
155         /** execute node template */
156         val executionServiceOutput = nodeTemplateExecutionService
157             .executeNodeTemplate(bluePrintRuntimeService, nodeTemplateName, nodeInput)
158
159         return when (executionServiceOutput.status.message) {
160             BlueprintConstants.STATUS_FAILURE -> EdgeLabel.FAILURE
161             else -> EdgeLabel.SUCCESS
162         }
163     }
164
165     override suspend fun skipNode(
166         node: Graph.Node,
167         nodeInput: ExecutionServiceInput,
168         nodeOutput: ExecutionServiceOutput
169     ): EdgeLabel {
170         return EdgeLabel.SUCCESS
171     }
172
173     override suspend fun cancelNode(
174         node: Graph.Node,
175         nodeInput: ExecutionServiceInput,
176         nodeOutput: ExecutionServiceOutput
177     ): EdgeLabel {
178         TODO("not implemented")
179     }
180
181     override suspend fun restartNode(
182         node: Graph.Node,
183         nodeInput: ExecutionServiceInput,
184         nodeOutput: ExecutionServiceOutput
185     ): EdgeLabel {
186         TODO("not implemented")
187     }
188 }