I am implementing a state pattern in Java for my application and need few clarifications.
The state machine has 5 states State 1 to State 5. The are a total of 5 events(Event1 to Event5) which causes the state transition. Not all events are applicable in all the states. If the event is not applicable in that particular state the application will throw exception.
When the state machine gets initialized it starts with state1.
Following is the interface and the context class.
/*
Interface defining the possible events in each state.
Each Implementer will handle event in a different manner.
*/
public interface State {
/*
Handlers for each event. Each Implementer will handle the vent in a different manner.
*/
public void handleEvent1(StateContext context);
public void handleEvent2(StateContext context);
public void handleEvent3(StateContext context);
public void handleEvent4(StateContext context);
public void handleEvent5(StateContext context);
// Method to enter state and do some action.
public void enter(StateContext context);
// Method to exit state and do some clean-up activity on exit .
public void exit(StateContext context);
}
/*
Context class which will handle the state change and delegate event to appropriate event handler of current state
*/
Class StateContext {
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private State currentState = null;
StateContext() {
currentState = new State1();
}
//Handle event1 and pass it to the appropriate event handler for the current state.
public void handleEvent1() {
currentState.handleEvent1();
}
.
.
.
//Handle event5 and pass it to the appropriate event handler for the current state.
public void handleEvent5() {
currentState.handleEvent5();
}
// Method to change the state.
// This method will be called by each state when it needs to transit to a new state.
public void changeState(State newState) {
accquireLock();
currentState.exit();
currentState = newState;
currentState.enter();
}
// Release read lock and accquire write lock
public void accquireLock() {
lock.readLock().unlock()
lock.writeLock().lock();
}
// accquire readlock and release write lock
public void releaseLock() {
lock.readLock().lock()
lock.writeLock().unlock();
}
}
To make it simple, I have provided implementation for only one state.
public class State1 implements State {
public void handleEvent1(StateContext context) {
//Hand1e Event 1
}
.
.
.
public void handleEvent5(StateContext context) {
//Handle Event 5
}
public void enter(StateContext context) {
//Release the lock here
context.releaseLock();
/*Here is my question. Is it a good java practice to expose accquire and release lock in Context object. And use the exposed method here to release lock.
*/
// Do some action on entering the state. This may take few seconds to finish
}
}
I want to release the lock only after entering state. Also I don't want to hold the lock till enter() finishes. If I hold the lock till enter finishes I cannot handle other events and it may get timed-out.For some events (which don't really change the state) we need to read the state and based on the state we can process them or ignore them. If I don't release lock they cannot be processed.Also in some other cases if an event comes to shutdown(this event changes the state) the state machine while enter() is in progress I cannot handle it. I have to shutdown the state machine immediately since it is not appropriate in continuing the enter() after shutdown event has come.
My Question: Is it good java programming practice to expose the accquireLock and releaseLock as an API in Context class and use them in each state class.
Thanks, Arun