@@ -6,13 +6,11 @@ import at.ac.uibk.dps.cirrina.csm.Csml.EventChannel
66import at.ac.uibk.dps.cirrina.execution.`object`.StateMachine.Factory
77import at.ac.uibk.dps.cirrina.spec.Instance
88import at.ac.uibk.dps.cirrina.spec.StateMachine as StateMachineSpec
9- import at.ac.uibk.dps.cirrina.spec.Transition as TransitionSpec
109import dagger.assisted.Assisted
1110import dagger.assisted.AssistedFactory
1211import dagger.assisted.AssistedInject
1312import io.micrometer.observation.Observation
1413import io.micrometer.observation.ObservationRegistry
15- import kotlin.collections.get
1614import kotlin.properties.Delegates
1715import kotlinx.coroutines.*
1816import kotlinx.coroutines.channels.Channel
@@ -23,6 +21,8 @@ private val logger = KotlinLogging.logger {}
2321
2422private const val VAR_PREFIX = " $"
2523
24+ private data class ActiveTransition (val transition : Transition , val isOr : Boolean )
25+
2626class StateMachine
2727@AssistedInject
2828internal constructor (
@@ -51,6 +51,25 @@ internal constructor(
5151 private val stateInstances =
5252 specification.vertexSet().associate { it.name to stateFactory.create(it, this ) }
5353
54+ private val onTransitions: Map <String , Map <String , List <Transition >>> =
55+ specification.vertexSet().associate { state ->
56+ state.name to
57+ specification
58+ .outgoingEdgesOf(state)
59+ .filter { it.event != null }
60+ .groupBy { it.event!! }
61+ .mapValues { (_, specs) -> specs.map { transitionFactory.create(it) } }
62+ }
63+
64+ private val alwaysTransitions: Map <String , List <Transition >> =
65+ specification.vertexSet().associate { state ->
66+ state.name to
67+ specification
68+ .outgoingEdgesOf(state)
69+ .filter { it.event == null }
70+ .map { transitionFactory.create(it) }
71+ }
72+
5473 private val started = CompletableDeferred <Unit >()
5574 private val eventChannel = Channel <Event >(Channel .UNLIMITED )
5675 private var activeState: State ? = null
@@ -131,10 +150,9 @@ internal constructor(
131150 }
132151 }
133152
134- private fun handleEvent (event : Event ): Transition ? {
153+ private fun handleEvent (event : Event ): ActiveTransition ? {
135154 val current = activeState ? : error(" received event '$event ' before entering initial state" )
136- val candidates =
137- specification.getOnTransitionsFromStateByEventName(current.specification, event.topic)
155+ val candidates = onTransitions[current.specification.name]?.get(event.topic).orEmpty()
138156
139157 if (candidates.isEmpty()) return null
140158
@@ -153,36 +171,36 @@ internal constructor(
153171 return true
154172 }
155173
156- private fun step (initialTransition : Transition ) {
157- var currentTransition : Transition ? = initialTransition
174+ private fun step (initialTransition : ActiveTransition ) {
175+ var currentActive : ActiveTransition ? = initialTransition
158176
159- while (currentTransition != null ) {
160- val transition = currentTransition
177+ while (currentActive != null ) {
178+ val transition = currentActive.transition
179+ val isOr = currentActive.isOr
161180
162181 if (transition.isInternal) {
163- doTransition(transition)
182+ doTransition(transition, isOr )
164183 return
165184 }
166185
167- val target =
168- stateInstances[transition.targetStateName]
169- ? : error(" target state '${transition.targetStateName} ' not found" )
186+ val targetName = transition.targetStateName(isOr) ? : error(" target state string is null" )
187+ val target = stateInstances[targetName] ? : error(" target state '$targetName ' not found" )
170188 val current = activeState ? : error(" no active state to transition from" )
171189
172190 doExit(current)
173- doTransition(transition)
191+ doTransition(transition, isOr )
174192
175- currentTransition = doEnter(target)
193+ currentActive = doEnter(target)
176194 }
177195 }
178196
179- private fun trySelect (transitions : List <TransitionSpec >, evalExtent : Extent ): Transition ? {
197+ private fun trySelect (transitions : List <Transition >, evalExtent : Extent ): ActiveTransition ? {
180198 val selected =
181199 transitions.mapNotNull { transition ->
182- val result = transition.evaluate(evalExtent)
200+ val spec = transition.specification
183201 when {
184- result -> transitionFactory.create (transition, isOr = false )
185- transition .or != null -> transitionFactory.create (transition, isOr = true )
202+ spec.evaluate(evalExtent) -> ActiveTransition (transition, isOr = false )
203+ spec .or != null -> ActiveTransition (transition, isOr = true )
186204 else -> null
187205 }
188206 }
@@ -194,11 +212,11 @@ internal constructor(
194212 }
195213 }
196214
197- private fun doEnter (state : State ): Transition ? =
215+ private fun doEnter (state : State ): ActiveTransition ? =
198216 Observation .createNotStarted(" stateMachine.enter" , observationRegistry)
199217 .lowCardinalityKeyValue(" stateMachine.instanceName" , name)
200218 .lowCardinalityKeyValue(" state.name" , state.specification.name)
201- .observe<Transition ?> {
219+ .observe<ActiveTransition ?> {
202220 activeState = state
203221
204222 execute(state.entryActions, state)
@@ -209,7 +227,7 @@ internal constructor(
209227 handleTermination()
210228
211229 if (! isTerminated()) {
212- trySelect(specification.getAlwaysTransitionsFromState( state.specification), extent)
230+ trySelect(alwaysTransitions[ state.specification.name].orEmpty( ), extent)
213231 } else null
214232 }
215233
@@ -222,9 +240,9 @@ internal constructor(
222240 execute(state.exitActions, state)
223241 }
224242
225- private fun doTransition (transition : Transition ) =
243+ private fun doTransition (transition : Transition , isOr : Boolean ) =
226244 Observation .createNotStarted(" stateMachine.transition" , observationRegistry).observe {
227- if (! transition. isOr) {
245+ if (! isOr) {
228246 execute(transition.actions, activeState!! )
229247 }
230248 }
0 commit comments