2aa408527d77f16aeeb19882b2f7ebfa1ae6a2ea
[ccsdk/cds.git] /
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         /** execute node template */
145         val executionServiceOutput = nodeTemplateExecutionService
146             .executeNodeTemplate(bluePrintRuntimeService, nodeTemplateName, nodeInput)
147
148         return when (executionServiceOutput.status.message) {
149             BluePrintConstants.STATUS_FAILURE -> EdgeLabel.FAILURE
150             else -> EdgeLabel.SUCCESS
151         }
152     }
153
154     override suspend fun skipNode(
155         node: Graph.Node,
156         nodeInput: ExecutionServiceInput,
157         nodeOutput: ExecutionServiceOutput
158     ): EdgeLabel {
159         return EdgeLabel.SUCCESS
160     }
161
162     override suspend fun cancelNode(
163         node: Graph.Node,
164         nodeInput: ExecutionServiceInput,
165         nodeOutput: ExecutionServiceOutput
166     ): EdgeLabel {
167         TODO("not implemented")
168     }
169
170     override suspend fun restartNode(
171         node: Graph.Node,
172         nodeInput: ExecutionServiceInput,
173         nodeOutput: ExecutionServiceOutput
174     ): EdgeLabel {
175         TODO("not implemented")
176     }
177 }