|
|||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Objectorg.jboss.util.CloneableObject
org.jboss.util.state.StateMachine
A generalization of a programmable finite-state machine (with a twist).
A state machine is backed up by a StateMachine.Model
which simply provides data encapsulation. The machine starts
in the initial state, which must not be null. Care must be
taken to ensure that the machine state is not corrupted
due to invalid modifications of the model. Best to leave the
model alone once the machine has been created.
Provides change notification via StateMachine.ChangeListener
objects.
When a listener throws an exception it will not corrupt the state
machine; it may however corrupt any application state which is
dependent on the listener mechanism. For this reason listeners
should handle exceptions which might be thrown or the client
application should handle recovery of such corruption by catching
those undeclared exceptions.
State instances which implement StateMachine.Acceptable
will
be consulted to determine if a state is acceptable. If such a
state throws an exception the state of the machine will not change.
The exception will be propagated to the client application for processing.
Durring state change events, such as acceptting and resetting,
if the previous and/or current state objects implement
StateMachine.ChangeListener
they will be notified in that order.
State machine is not synchronized. Use makeSynchronized(org.jboss.util.state.StateMachine, java.lang.Object)
to make a machine thread safe.
Example of how to program a state machine:
// Create some states
State NEW = new State(0, "NEW");
State INITALIZEING = new State(1, "INITALIZING");
State INITIALIZED = new State(2, "INITIALIZED");
State STARTING = new State(3, "STARTING");
State STARTED = new State(4, "STARTED");
State FAILED = new State(5, "FAILED");
// Create a model for the state machine
StateMachine.Model model = new DefaultStateMachineModel();
// Add some state mappings
model.addState(NEW, INITIALIZING);
model.addState(INITIALIZING, new State[] { INITIALIZED, FAILED });
model.addState(INITIALIZED, new State[] { STARTING });
model.addState(STARTING, new State[] { STARTED, FAILED });
// These states are final (they do not accept any states)
model.addState(STARTED);
model.addState(FAILED);
// Set the initial state
model.setInitialState(NEW);
// Create the machine
StateMachine machine = new StateMachine(model);
Once you have created a StateMachine instance, using it is simple:
// Change to the INITIALIZING state
machine.transition(INITIALIZING);
// Change to the INITIALIZED state
machine.transition(INITIALIZED); *
// Try to change to an invalid state:
try {
// As programmed, the INITIALIZED state does not accept the NEW
// state, it only accepts the STARTING state.
machine.transition(NEW);
}
catch (IllegalStateException e) {
// Do something with the exception; The state of the machine is
// still INITIALIZED.
}
// Transition to a final state
machine.transition(STARTING);
machine.transition(FAILED);
// Any attempt to transition to any state will fail, the FAILED is
// a final state, as it does not accept any other states.
// Reset the machine so we can use it again
machine.reset();
// The state of the machine is now the same as it was when the
// state machine was first created (short of any added change
// listeners... they do not reset).
Nested Class Summary | |
static interface |
StateMachine.Acceptable
Provides the interface for dynmaic state acceptability. |
static class |
StateMachine.ChangeEvent
An event for state change notifications. |
static interface |
StateMachine.ChangeListener
A listener for state change events. |
static interface |
StateMachine.Model
Defines the data model required by a StateMachine . |
Nested classes inherited from class org.jboss.util.CloneableObject |
CloneableObject.Cloneable |
Field Summary | |
protected List |
changeListeners
The list of change listeners which are registered. |
protected StateMachine.Model |
model
The data model for the machine. |
Constructor Summary | |
StateMachine(StateMachine.Model model)
Construct a state machine with the given model. |
Method Summary | |
void |
addChangeListener(StateMachine.ChangeListener listener)
Add a state change listener. |
protected StateMachine.ChangeEvent |
changeState(State state)
Change the state of the machine and send change events to all listeners and to the previous and new state objects if they implement StateMachine.ChangeListener . |
Set |
finalStates()
Return all states which are final. |
protected void |
fireStateChanged(StateMachine.ChangeEvent event)
Send a change event to all listeners. |
State |
getCurrentState()
Returns the current state of the machine. |
State |
getInitialState()
Returns the initial state of the machine. |
StateMachine.Model |
getModel()
Return the model which provides data encapsulation for the machine. |
boolean |
isAcceptable(State state)
Check if the current state can accept a transition to the given state. |
boolean |
isCurrentState(State state)
Check if the given state is the current state. |
boolean |
isInitialState(State state)
Check if the given state is the initial state. |
boolean |
isStateFinal()
Determine if the current state is final. |
boolean |
isStateFinal(State state)
Determine if the given state is final. |
static StateMachine |
makeImmutable(StateMachine machine)
Return a immutable state machine. |
static StateMachine |
makeImmutable(StateMachine machine,
boolean hideModel)
Return a immutable state machine. |
static StateMachine |
makeSynchronized(StateMachine machine)
Return a synchronized state machine. |
static StateMachine |
makeSynchronized(StateMachine machine,
Object mutex)
Return a synchronized state machine. |
void |
removeChangeListener(StateMachine.ChangeListener listener)
Remove a state change listener. |
void |
reset()
Reset the state machine. |
String |
toString()
Returns a human readable snapshot of the current state of the machine. |
void |
transition(State state)
Attempt to transition into the give state if the current state can accept it. |
Methods inherited from class org.jboss.util.CloneableObject |
clone |
Methods inherited from class java.lang.Object |
equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait |
Field Detail |
protected final StateMachine.Model model
protected final List changeListeners
Constructor Detail |
public StateMachine(StateMachine.Model model)
model
- The model for the machine; must not be null.Method Detail |
public String toString()
public StateMachine.Model getModel()
public State getCurrentState()
StateMachine.Model.getCurrentState()
,
getModel()
public State getInitialState()
StateMachine.Model.getInitialState()
,
getModel()
public boolean isAcceptable(State state)
If the current state is final or does not list the given state as
acceptable, then machine can not make the transition.
The only exception to this rule is if the current state implements
StateMachine.Acceptable
; then the state is asked to determine acceptance.
If the state returns false then the acceptable list will be consulted
to make the final descision.
The mapped version of the state (not the version passed to accept) will be used to check acceptance.
state
- The state check.
IllegalArgumentException
- State not found in model.public void transition(State state)
The mapped version of the state (not the version passed to transition) will be used in the transition.
state
- The state to transiiton into.
IllegalStateException
- State can not be accepted, current
state is final or non-acceptable.public void reset()
This will transition to the initial state and send change
events to all listeners and to all accepting states which
implement StateMachine.ChangeListener
. Each state will only
be notified once.
protected StateMachine.ChangeEvent changeState(State state)
StateMachine.ChangeListener
.
public Set finalStates()
isStateFinal(State)
public boolean isStateFinal(State state)
Determing the finality of states which implement
StateMachine.Acceptable
is costly.
state
- The state to check for finality; must not be null.
IllegalArgumentException
- State not found in model.public boolean isStateFinal()
isStateFinal(State)
public boolean isCurrentState(State state)
state
- The state to check.
public boolean isInitialState(State state)
state
- The state to check.
public void addChangeListener(StateMachine.ChangeListener listener)
listener
- The listener to add; must not be nullpublic void removeChangeListener(StateMachine.ChangeListener listener)
If the give value is null then this is a non-operation.
protected void fireStateChanged(StateMachine.ChangeEvent event)
Listeners are invoked in the same order which they have been added.
This method (as well as add and remove methods) are protected from concurrent modification exceptions.
public static StateMachine makeSynchronized(StateMachine machine, Object mutex)
machine
- State machine to synchronize; must not be null.mutex
- The object to lock on; null to use returned instance.
public static StateMachine makeSynchronized(StateMachine machine)
machine
- State machine to synchronize; must not be null.
public static StateMachine makeImmutable(StateMachine machine, boolean hideModel)
Immutable state machines can not be transitioned or reset; methods will throw a UnsupportedOperationException.
If model is not hidden, then users can still mess up the model if they want, thus corrupting the state machine.
machine
- State machine to make immutable; must not be null.hideModel
- Make the model inaccessable too.
public static StateMachine makeImmutable(StateMachine machine)
Immutable state machines can not be transitioned or reset; methods will throw a UnsupportedOperationException.
machine
- State machine to make immutable; must not be null.
|
|||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |