|
1 | 1 | package at.ac.uibk.dps.cirrina.execution.`object` |
2 | 2 |
|
3 | 3 | import at.ac.uibk.dps.cirrina.csm.Csml.EventChannel |
4 | | -import at.ac.uibk.dps.cirrina.execution.service.ServiceImplementation |
5 | 4 | import at.ac.uibk.dps.cirrina.execution.service.ServiceImplementationSelector |
6 | | -import io.micrometer.core.instrument.MeterRegistry |
7 | 5 | import kotlinx.coroutines.CoroutineScope |
8 | 6 | import kotlinx.coroutines.launch |
9 | 7 | import mu.KotlinLogging |
10 | 8 |
|
11 | 9 | private val logger = KotlinLogging.logger {} |
12 | 10 |
|
13 | | -data class CommandExecutionContext( |
14 | | - val scope: Scope, |
15 | | - val serviceImplementationSelector: ServiceImplementationSelector, |
16 | | - val stateMachineEventHandler: StateMachine.StateMachineEventHandler, |
17 | | - val coroutineScope: CoroutineScope, |
18 | | - val raisingEvent: Event? = null, |
19 | | - val isDuring: Boolean = false, |
20 | | -) |
21 | | - |
22 | | -interface ActionCommandFactory { |
23 | | - fun create(action: Action, commandExecutionContext: CommandExecutionContext): ActionCommand |
24 | | -} |
25 | | - |
26 | | -class ActionCommandFactoryImpl(private val meterRegistry: MeterRegistry) : ActionCommandFactory { |
27 | | - override fun create( |
28 | | - action: Action, |
29 | | - commandExecutionContext: CommandExecutionContext, |
30 | | - ): ActionCommand = |
31 | | - when (action) { |
32 | | - is EvalAction -> EvalActionCommand(action, commandExecutionContext, this, meterRegistry) |
33 | | - is InvokeAction -> InvokeActionCommand(action, commandExecutionContext, this, meterRegistry) |
34 | | - is MatchAction -> MatchActionCommand(action, commandExecutionContext, this, meterRegistry) |
35 | | - is EmitAction -> EmitActionCommand(action, commandExecutionContext, this, meterRegistry) |
36 | | - is TimeoutAction -> TimeoutActionCommand(action, commandExecutionContext, this, meterRegistry) |
37 | | - is TimeoutResetAction -> |
38 | | - TimeoutResetActionCommand(action, commandExecutionContext, this, meterRegistry) |
39 | | - is LogAction -> LogActionCommand(action, commandExecutionContext, this, meterRegistry) |
40 | | - else -> error("unknown action type: ${action::class.simpleName}") |
41 | | - } |
42 | | -} |
43 | | - |
44 | 11 | interface Scope { |
45 | 12 | val extent: Extent |
46 | 13 | } |
47 | 14 |
|
48 | | -abstract class ActionCommand |
49 | | -internal constructor( |
50 | | - protected val commandExecutionContext: CommandExecutionContext, |
51 | | - protected val commandFactory: ActionCommandFactory, |
52 | | - protected val meterRegistry: MeterRegistry, |
| 15 | +class ActionExecutor( |
| 16 | + private val selector: ServiceImplementationSelector, |
| 17 | + private val eventHandler: StateMachine.StateMachineEventHandler, |
| 18 | + private val coroutineScope: CoroutineScope, |
53 | 19 | ) { |
54 | | - abstract fun execute(): List<ActionCommand> |
55 | | -} |
56 | | - |
57 | | -class EvalActionCommand |
58 | | -internal constructor( |
59 | | - private val evalAction: EvalAction, |
60 | | - commandExecutionContext: CommandExecutionContext, |
61 | | - commandFactory: ActionCommandFactory, |
62 | | - meterRegistry: MeterRegistry, |
63 | | -) : ActionCommand(commandExecutionContext, commandFactory, meterRegistry) { |
64 | | - override fun execute(): List<ActionCommand> = |
65 | | - evalAction.expression.execute(commandExecutionContext.scope.extent).run { emptyList() } |
66 | | -} |
67 | | - |
68 | | -class InvokeActionCommand |
69 | | -internal constructor( |
70 | | - private val invokeAction: InvokeAction, |
71 | | - commandExecutionContext: CommandExecutionContext, |
72 | | - commandFactory: ActionCommandFactory, |
73 | | - meterRegistry: MeterRegistry, |
74 | | -) : ActionCommand(commandExecutionContext, commandFactory, meterRegistry) { |
75 | | - private val logger = KotlinLogging.logger {} |
76 | | - |
77 | | - override fun execute(): List<ActionCommand> { |
78 | | - val service = selectServiceImplementation() |
79 | | - val input = prepareInput(commandExecutionContext.scope.extent) |
80 | | - |
81 | | - commandExecutionContext.coroutineScope.launch { |
82 | | - runCatching { service.invoke(input) } |
83 | | - .onSuccess { emitEvents(it) } |
84 | | - .onFailure { logger.error(it) { "service invocation failed" } } |
| 20 | + fun execute(action: Action, scope: Scope): List<Action> = |
| 21 | + when (action) { |
| 22 | + is EvalAction -> executeEval(action, scope) |
| 23 | + is InvokeAction -> executeInvoke(action, scope) |
| 24 | + is MatchAction -> executeMatch(action, scope) |
| 25 | + is EmitAction -> executeEmit(action, scope) |
| 26 | + is TimeoutAction -> listOf(action.triggers) |
| 27 | + is TimeoutResetAction -> emptyList() |
| 28 | + is LogAction -> executeLog(action, scope) |
| 29 | + else -> error("unknown action type: ${action::class.simpleName}") |
85 | 30 | } |
86 | 31 |
|
| 32 | + private fun executeEval(action: EvalAction, scope: Scope): List<Action> { |
| 33 | + action.expression.execute(scope.extent) |
87 | 34 | return emptyList() |
88 | 35 | } |
89 | 36 |
|
90 | | - private fun selectServiceImplementation(): ServiceImplementation = |
91 | | - commandExecutionContext.serviceImplementationSelector.select( |
92 | | - invokeAction.type, |
93 | | - invokeAction.mode, |
94 | | - ) ?: error("no service implementation found for type '${invokeAction.type}'") |
| 37 | + private fun executeInvoke(action: InvokeAction, scope: Scope): List<Action> { |
| 38 | + val service = |
| 39 | + selector.select(action.type, action.mode) |
| 40 | + ?: error("no service implementation found for type '${action.type}'") |
95 | 41 |
|
96 | | - private fun prepareInput(extent: Extent): List<ContextVariable> = |
97 | | - invokeAction.input.map { it.evaluate(extent) } |
| 42 | + val input = action.input.map { it.evaluate(scope.extent) } |
98 | 43 |
|
99 | | - private fun emitEvents(output: List<ContextVariable>) { |
100 | | - invokeAction.emits.forEach { eventTemplate -> |
101 | | - val event = eventTemplate.copy(data = output) |
102 | | - val handler = |
103 | | - when (event.channel) { |
104 | | - EventChannel.INTERNAL -> |
105 | | - commandExecutionContext.stateMachineEventHandler::propagateToParent |
106 | | - else -> commandExecutionContext.stateMachineEventHandler::emit |
| 44 | + coroutineScope.launch { |
| 45 | + runCatching { service.invoke(input) } |
| 46 | + .onSuccess { output -> |
| 47 | + action.emits.forEach { eventTemplate -> |
| 48 | + val emittedEvent = eventTemplate.copy(data = output) |
| 49 | + if (emittedEvent.channel == EventChannel.INTERNAL) { |
| 50 | + eventHandler.propagateToParent(emittedEvent) |
| 51 | + } else { |
| 52 | + eventHandler.emit(emittedEvent) |
| 53 | + } |
| 54 | + } |
107 | 55 | } |
108 | | - handler(event) |
| 56 | + .onFailure { logger.error(it) { "service invocation failed" } } |
109 | 57 | } |
110 | | - } |
111 | | -} |
112 | 58 |
|
113 | | -class MatchActionCommand |
114 | | -internal constructor( |
115 | | - private val matchAction: MatchAction, |
116 | | - commandExecutionContext: CommandExecutionContext, |
117 | | - commandFactory: ActionCommandFactory, |
118 | | - meterRegistry: MeterRegistry, |
119 | | -) : ActionCommand(commandExecutionContext, commandFactory, meterRegistry) { |
120 | | - override fun execute(): List<ActionCommand> { |
121 | | - val extent = commandExecutionContext.scope.extent |
122 | | - |
123 | | - val selectedActions: List<Action> = |
124 | | - matchAction.cases.entries |
125 | | - .filter { (expression, _) -> expression.execute(extent) == true } |
126 | | - .flatMap { it.value } |
127 | | - .ifEmpty { listOfNotNull(matchAction.default) } |
128 | | - |
129 | | - return selectedActions.map { commandFactory.create(it, commandExecutionContext) } |
| 59 | + return emptyList() |
130 | 60 | } |
131 | | -} |
132 | 61 |
|
133 | | -class EmitActionCommand |
134 | | -internal constructor( |
135 | | - private val emitAction: EmitAction, |
136 | | - commandExecutionContext: CommandExecutionContext, |
137 | | - commandFactory: ActionCommandFactory, |
138 | | - meterRegistry: MeterRegistry, |
139 | | -) : ActionCommand(commandExecutionContext, commandFactory, meterRegistry) { |
140 | | - override fun execute(): List<ActionCommand> { |
141 | | - val event = |
142 | | - emitAction.event.evaluateData(commandExecutionContext.scope.extent).run { |
143 | | - val target = emitAction.target?.execute(commandExecutionContext.scope.extent) as? String |
| 62 | + private fun executeMatch(action: MatchAction, scope: Scope): List<Action> = |
| 63 | + action.cases.entries |
| 64 | + .filter { (expression, _) -> expression.execute(scope.extent) == true } |
| 65 | + .flatMap { it.value } |
| 66 | + .ifEmpty { listOfNotNull(action.default) } |
| 67 | + |
| 68 | + private fun executeEmit(action: EmitAction, scope: Scope): List<Action> { |
| 69 | + val emittedEvent = |
| 70 | + action.event.evaluateData(scope.extent).run { |
| 71 | + val target = action.target?.execute(scope.extent) as? String |
144 | 72 | if (target != null) copy(target = target) else this |
145 | 73 | } |
146 | 74 |
|
147 | | - with(commandExecutionContext.stateMachineEventHandler) { |
148 | | - if (event.channel == EventChannel.INTERNAL) propagateToParent(event) else emit(event) |
| 75 | + with(eventHandler) { |
| 76 | + if (emittedEvent.channel == EventChannel.INTERNAL) propagateToParent(emittedEvent) |
| 77 | + else emit(emittedEvent) |
149 | 78 | } |
150 | 79 |
|
151 | 80 | return emptyList() |
152 | 81 | } |
153 | | -} |
154 | | - |
155 | | -class TimeoutActionCommand |
156 | | -internal constructor( |
157 | | - private val timeoutAction: TimeoutAction, |
158 | | - commandExecutionContext: CommandExecutionContext, |
159 | | - commandFactory: ActionCommandFactory, |
160 | | - meterRegistry: MeterRegistry, |
161 | | -) : ActionCommand(commandExecutionContext, commandFactory, meterRegistry) { |
162 | | - override fun execute(): List<ActionCommand> = |
163 | | - listOf(commandFactory.create(timeoutAction.triggers, commandExecutionContext)) |
164 | | -} |
165 | | - |
166 | | -class TimeoutResetActionCommand |
167 | | -internal constructor( |
168 | | - val timeoutResetAction: TimeoutResetAction, |
169 | | - commandExecutionContext: CommandExecutionContext, |
170 | | - commandFactory: ActionCommandFactory, |
171 | | - meterRegistry: MeterRegistry, |
172 | | -) : ActionCommand(commandExecutionContext, commandFactory, meterRegistry) { |
173 | | - override fun execute(): List<ActionCommand> = emptyList() |
174 | | -} |
175 | | - |
176 | | -class LogActionCommand |
177 | | -internal constructor( |
178 | | - private val logAction: LogAction, |
179 | | - commandExecutionContext: CommandExecutionContext, |
180 | | - commandFactory: ActionCommandFactory, |
181 | | - meterRegistry: MeterRegistry, |
182 | | -) : ActionCommand(commandExecutionContext, commandFactory, meterRegistry) { |
183 | | - override fun execute(): List<ActionCommand> { |
184 | | - logAction.message.execute(commandExecutionContext.scope.extent).toString().also { |
185 | | - logger.info(it) |
186 | | - } |
187 | 82 |
|
| 83 | + private fun executeLog(action: LogAction, scope: Scope): List<Action> { |
| 84 | + action.message.execute(scope.extent).toString().also { logger.info(it) } |
188 | 85 | return emptyList() |
189 | 86 | } |
190 | 87 | } |
0 commit comments