State machine management system, provide easy implementation of complex state flow of a system
SMMS provides state management in simple and effective way, has capability of handling events synchronously and asynchronously both.
To write a state machine system in easy and effective way
If your system requires managing complex states this tool as your life saver
There are two types of state machine
Creating async state machine
new StateMachine(new ContextObject(), 10, 3);
arguments are
Creating sync state machine
new SyncStateMachine(new ContextObject());
arguments are
An event can be posted to stateMachine, postEvent on stateMachine calls current state’s onEvent method. On async StateMachine’s postEvent call return immediately and perform state’s onEvent method on a separate thread but on sync StateMachine it returns when state’s onEvent completes, there is also postEventAndWait(event, waitTimeInMillis) method on async stateMachine that waits for the given time and throws exception if time expires.
stateMachine.postEvent(event);
stateMachine.postEventAndWait(event, timeInMillis);
an event is a subClass of Object class and will be passed as argument on state’s onEvent method
Initial state of a state machine (beginning state)
stateMachine.initState(new BeginState());
where BeginState is subClass of State class
To create a state extends State class, it primarily asks to implement onEntry, onEvent and onExit
onEntry
public void onEntry(Object context, State fromState) throws StateException
onExit
public void onExit(Object context, State toState) throws StateException
onEvent
protected State onEvent(Object context, Object theEvent) throws StateException {
other functionalities can be overridden
*todo: cover detailed explanation**
Let’s write a system which manage states as below diagram
Complete implementation can be found here
States
Click to see state complete implementation
In above diagram system has 3 states (Opened, Closed and Locked)
Opened State implementation
if CloseEvent is posted on this state then state will be changed to Closed**
public class OpenedState extends AbstractState {
private static final Logger log = Logger.getLogger(OpenedState.class);
public OpenedState(int iType) {
super(iType);
}
@Override
public void onEntry(Object context, State fromState) throws StateException {
log.info("entering in Opened state");
}
@Override
protected State onEvent(Object context, Object theEvent) throws StateException {
if (theEvent instanceof CloseEvent) {
return StateFactory.getInstance().getState(DoorStates.CLOSED);
}
return null;
}
@Override
public void onExit(Object context, State toState) throws StateException {
log.info("exiting in Opened state");
}
}
Closed State implementation
if theEvent is of type LockEvent change state to Locked similarly for OpenEvent.
public class ClosedState extends AbstractState {
private static final Logger log = Logger.getLogger(ClosedState.class);
public ClosedState(int iType) {
super(iType);
}
@Override
public void onEntry(Object context, State fromState) throws StateException {
log.info("entering in Closed state");
}
@Override
protected State onEvent(Object context, Object theEvent) throws StateException {
if (theEvent instanceof LockEvent) {
return StateFactory.getInstance().getState(DoorStates.LOCKED);
}
if (theEvent instanceof OpenEvent) {
return StateFactory.getInstance().getState(DoorStates.OPENED);
}
return null;
}
@Override
public void onExit(Object context, State toState) throws StateException {
log.info("exiting in Locked state");
}
}
Locked State implementation
if theEvent is of type UnlockEvent change state to Closed**
public class LockedState extends AbstractState {
private static final Logger log = Logger.getLogger(LockedState.class);
public LockedState(int iType) {
super(iType);
}
@Override
public void onEntry(Object context, State fromState) throws StateException {
log.info("entering in Locked state");
}
@Override
protected State onEvent(Object context, Object theEvent) throws StateException {
if (theEvent instanceof UnlockEvent) {
return StateFactory.getInstance().getState(DoorStates.CLOSED);
}
return null;
}
@Override
public void onExit(Object context, State toState) throws StateException {
log.info("exiting in Locked state");
}
}
Events
There are four events can be performed on system (Open, Close, Lock and Unlock)
Create an empty class per events for identifying event like below
State Handler Post an event to change the state
public class StateHandler {
public static final int MAX_EVENTS = 40;
public static final int THREAD_POOL_SIZE = 3;
private StateMachine stateMachine;
public boolean init() {
stateMachine = new StateMachine(new DummyLocker(), MAX_EVENTS, THREAD_POOL_SIZE);
stateMachine.initState(StateFactory.getInstance().getState(DoorStates.OPENED));
return true;
}
public boolean open() {
//return stateMachine.postEvent(new OpenEvent());
try {
return stateMachine.postEventAndWait(new OpenEvent(), 2000);
} catch (Throwable e) {
System.out.println(e.getMessage());
}
return false;
}
public boolean close() {
//return stateMachine.postEvent(new CloseEvent());
try {
return stateMachine.postEventAndWait(new CloseEvent(), 2000);
} catch (Throwable e) {
System.out.println(e.getMessage());
}
return false;
}
public boolean lock() {
//return stateMachine.postEvent(new LockEvent());
try {
return stateMachine.postEventAndWait(new LockEvent(), 2000);
} catch (Throwable e) {
System.out.println(e.getMessage());
}
return false;
}
public boolean unlock() {
//return stateMachine.postEvent(new UnlockEvent());
try {
return stateMachine.postEventAndWait(new UnlockEvent(), 2000);
} catch (Throwable e) {
System.out.println(e.getMessage());
}
return false;
}
public String getState() {
return DoorStates.getState(stateMachine.getState().getStateType());
}
public void shutDown() {
stateMachine.shutDown();
}
public static class DummyLocker {
}
}
Example of stateHandler
public class DoorStateTest {
static {
BasicConfigurator.configure();
Logger.getRootLogger().setLevel(Level.INFO);
}
public static void main(String[] args) {
// begin
StateHandler stateHandler = new StateHandler();
stateHandler.init();
System.out.println("Initially locker was -> " + stateHandler.getState());
// try closing locker
stateHandler.close();
System.out.println("Locker is -> " + stateHandler.getState());
// try opening again
stateHandler.open();
System.out.println("Locker is -> " + stateHandler.getState());
// try locking on open nothing will happen
stateHandler.lock();
System.out.println("Locker is -> " + stateHandler.getState());
// try close and lock
stateHandler.close();
stateHandler.lock();
System.out.println("Locker is -> " + stateHandler.getState());
stateHandler.unlock();
System.out.println("Locker is -> " + stateHandler.getState());
stateHandler.shutDown();
}
}
Output is