Permalink
Cannot retrieve contributors at this time
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
113 lines (84 sloc)
3.38 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package koob.fsm | |
import koob.command.Command | |
import koob.event.Event | |
import koob.fsm.state.State | |
import groovy.util.logging.Slf4j | |
@Slf4j | |
class FiniteStateMachine { | |
String parent | |
String initialState | |
String previousState | |
String currentState | |
List<Grammar> transitions = [] | |
/** | |
* Defines a memento of state(s) with valid state transitions while brokering the runtime transition between states | |
* @param startingState | |
*/ | |
FiniteStateMachine(Class<State> startingState){ | |
assert startingState, "You need to provide an initial state" | |
initialState = startingState.canonicalName | |
currentState = startingState.canonicalName | |
parent = callerClassName | |
} | |
/** | |
* creates an instance of grammar to be used for each FSM DSL declaration | |
*/ | |
Grammar record() { | |
Grammar.newInstance(this) | |
} | |
/** | |
* register the FSM dsl transitions | |
* @param grammar | |
*/ | |
void registerTransition(Grammar grammar) { | |
transitions << grammar | |
} | |
/** | |
* Actor system onRecieve handler will process messages in an orderly fashion through the FSM via this method | |
* if the transition closure returns a Guard.class the state machine will stay put. | |
*/ | |
def fire(e) { | |
if (e instanceof Command) { | |
def command = e | |
def thisState = this.currentState | |
if (e instanceof String) | |
log.info(e) | |
else | |
e = e.class.canonicalName | |
/** | |
* look for qualifying transitions | |
*/ | |
def transitionMatches = transitions.findAll { Grammar it -> | |
(e in it.eventMatches && thisState == it.fromState) || | |
(e in it.eventMatches && it.fromState.contains("state.Any")) | |
} | |
if (transitionMatches.size()){ | |
transitionMatches.each { Grammar it -> | |
// log.info "[FSM:MATCH] $parent with command:($e) on currentState:(${currentState}) for grammar: (${it.toString()})" | |
def result = it.transition(command) | |
// check if transition closure was guarded for 1 or more domain specific reason | |
if (result instanceof Guard) { | |
log.info "FSM $parent: guarded transition for ${it.fromState} >> ${it.toState} becuase ${result.reason}" | |
} | |
// transition closure executed properly so change the finite state | |
else { | |
this.previousState = this.currentState | |
this.currentState = it.toState | |
// log.info "fsm setPreviousState: ${this.previousState}" | |
// log.info "fsm setCurrentState: ${this.currentState}" | |
} | |
} | |
} | |
return currentState | |
} | |
} | |
void reset() { | |
currentState = initialState | |
} | |
public void showState(){ | |
log.info("[FSM:STATUS] for $parent is reporting its current state as: ${currentState.toString()} from previous state of: ${previousState} with initialState of: ${initialState}") | |
} | |
private String getCallerClassName(){ | |
Thread.currentThread().getStackTrace().find { it.className.contains("koob") && !it.className.contains("FSM") && !it.className.contains("koob.fsm.FiniteStateMachine") }?.className | |
} | |
} |