Merge "Creating findOneBluePrintModel (configuration)"
[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.BluePrintWorkFlowService
35 import org.onap.ccsdk.cds.controllerblueprints.core.service.NodeExecuteMessage
36 import org.onap.ccsdk.cds.controllerblueprints.core.service.NodeSkipMessage
37 import org.onap.ccsdk.cds.controllerblueprints.core.service.WorkflowExecuteMessage
38 import org.springframework.beans.factory.config.ConfigurableBeanFactory
39 import org.springframework.context.annotation.Scope
40 import org.springframework.stereotype.Service
41
42 @Service("imperativeWorkflowExecutionService")
43 class ImperativeWorkflowExecutionService(
44     private val imperativeBluePrintWorkflowService: BluePrintWorkFlowService<ExecutionServiceInput, ExecutionServiceOutput>
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 imperativeBluePrintWorkflowService.executeWorkflow(
61             graph, bluePrintRuntimeService,
62             executionServiceInput
63         )
64     }
65 }
66
67 @Service
68 @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
69 open class ImperativeBluePrintWorkflowService(private val nodeTemplateExecutionService: NodeTemplateExecutionService) :
70     AbstractBluePrintWorkFlowService<ExecutionServiceInput, ExecutionServiceOutput>() {
71
72     val log = logger(ImperativeBluePrintWorkflowService::class)
73
74     lateinit var bluePrintRuntimeService: BluePrintRuntimeService<*>
75     lateinit var executionServiceInput: ExecutionServiceInput
76     lateinit var workflowName: String
77
78     override suspend fun executeWorkflow(
79         graph: Graph,
80         bluePrintRuntimeService: BluePrintRuntimeService<*>,
81         input: ExecutionServiceInput
82     ): ExecutionServiceOutput {
83         this.graph = graph
84         this.bluePrintRuntimeService = bluePrintRuntimeService
85         this.executionServiceInput = input
86         this.workflowName = this.executionServiceInput.actionIdentifiers.actionName
87         this.workflowId = bluePrintRuntimeService.id()
88         val output = CompletableDeferred<ExecutionServiceOutput>()
89         val startMessage = WorkflowExecuteMessage(input, output)
90         val workflowActor = workflowActor()
91         if (!workflowActor.isClosedForSend) {
92             workflowActor.send(startMessage)
93         } else {
94             throw BluePrintProcessorException("workflow($workflowActor) actor is closed")
95         }
96         return output.await()
97     }
98
99     override suspend fun initializeWorkflow(input: ExecutionServiceInput): EdgeLabel {
100         return EdgeLabel.SUCCESS
101     }
102
103     override suspend fun prepareWorkflowOutput(): ExecutionServiceOutput {
104         val wfStatus = Status().apply {
105             if (exceptions.isNotEmpty()) {
106                 exceptions.forEach {
107                     val errorMessage = it.message ?: ""
108                     bluePrintRuntimeService.getBluePrintError().addError(errorMessage)
109                     log.error("workflow($workflowId) exception :", it)
110                 }
111                 message = BluePrintConstants.STATUS_FAILURE
112             } else {
113                 message = BluePrintConstants.STATUS_SUCCESS
114             }
115             eventType = EventType.EVENT_COMPONENT_EXECUTED.name
116         }
117         return ExecutionServiceOutput().apply {
118             commonHeader = executionServiceInput.commonHeader
119             actionIdentifiers = executionServiceInput.actionIdentifiers
120             status = wfStatus
121         }
122     }
123
124     override suspend fun prepareNodeExecutionMessage(node: Graph.Node):
125             NodeExecuteMessage<ExecutionServiceInput, ExecutionServiceOutput> {
126         val nodeOutput = ExecutionServiceOutput().apply {
127             commonHeader = executionServiceInput.commonHeader
128             actionIdentifiers = executionServiceInput.actionIdentifiers
129         }
130         return NodeExecuteMessage(node, executionServiceInput, nodeOutput)
131     }
132
133     override suspend fun prepareNodeSkipMessage(node: Graph.Node):
134             NodeSkipMessage<ExecutionServiceInput, ExecutionServiceOutput> {
135         val nodeOutput = ExecutionServiceOutput().apply {
136             commonHeader = executionServiceInput.commonHeader
137             actionIdentifiers = executionServiceInput.actionIdentifiers
138         }
139         return NodeSkipMessage(node, executionServiceInput, nodeOutput)
140     }
141
142     override suspend fun executeNode(
143         node: Graph.Node,
144         nodeInput: ExecutionServiceInput,
145         nodeOutput: ExecutionServiceOutput
146     ): EdgeLabel {
147         log.info("Executing workflow($workflowName[${this.workflowId}])'s step($${node.id})")
148         val step = bluePrintRuntimeService.bluePrintContext().workflowStepByName(this.workflowName, node.id)
149         checkNotEmpty(step.target) { "couldn't get step target for workflow(${this.workflowName})'s step(${node.id})" }
150         val nodeTemplateName = step.target!!
151         /** execute node template */
152         val executionServiceOutput = nodeTemplateExecutionService
153             .executeNodeTemplate(bluePrintRuntimeService, nodeTemplateName, nodeInput)
154
155         return when (executionServiceOutput.status.message) {
156             BluePrintConstants.STATUS_FAILURE -> EdgeLabel.FAILURE
157             else -> EdgeLabel.SUCCESS
158         }
159     }
160
161     override suspend fun skipNode(
162         node: Graph.Node,
163         nodeInput: ExecutionServiceInput,
164         nodeOutput: ExecutionServiceOutput
165     ): EdgeLabel {
166         return EdgeLabel.SUCCESS
167     }
168
169     override suspend fun cancelNode(
170         node: Graph.Node,
171         nodeInput: ExecutionServiceInput,
172         nodeOutput: ExecutionServiceOutput
173     ): EdgeLabel {
174         TODO("not implemented")
175     }
176
177     override suspend fun restartNode(
178         node: Graph.Node,
179         nodeInput: ExecutionServiceInput,
180         nodeOutput: ExecutionServiceOutput
181     ): EdgeLabel {
182         TODO("not implemented")
183     }
184 }