java-fsm.code.net.openai.util.fsm.Machine Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of openaifsm Show documentation
Show all versions of openaifsm Show documentation
OpenAI FSM is used by Apache cTAKES.
It was originally developed out of sourceforge openAI group
The newest version!
/*****************************************************************************
* net.openai.fsm.Machine
*****************************************************************************
* @author JC on E
* @date 9/24/2000
* 2001 OpenAI Labs
*****************************************************************************/
package net.openai.util.fsm;
import java.util.Vector;
import java.io.Serializable;
import net.openai.util.fsm.event.MachineEvent;
import net.openai.util.fsm.event.MachineListener;
/**
* The controlling Machine class for the Finite State Machine
*/
public class Machine implements Serializable {
/** A handle to the start state. This will be the first state added
to the machine. */
private State startState = null;
/** A handle to the current state of the machine. */
private State currentState = null;
/** A dummy object to synchronize on across methods. */
private Integer syncObject = new Integer(-1);
/** A list of listeners for this Machine. */
private Vector listeners = new Vector();
/**
* Constructs a new Machine object with no start state.
*/
public Machine() {
}
/**
* Constructs a new Machine object.
*
* @param startState The State
object to begin on. This must
* be non-null
.
*/
public Machine(State startState) {
setStartState(startState);
}
/**
* Adds a MachineListener to this Machine that we will deliver events to.
*
* @param listener The MachineListener to add.
*/
public final void addMachineListener(MachineListener listener) {
if(listener == null)
throw new NullPointerException("Cannot add null listener.");
synchronized(listeners) {
if(!listeners.contains(listener))
listeners.addElement(listener);
}
}
/**
* Removes a MachineListener from this Machine.
*
* @param listener The MachineListener to remove.
*/
public final void removeMachineListener(MachineListener listener) {
if(listener == null)
return;
synchronized(listeners) {
listeners.removeElement(listener);
}
}
/**
* Sends a MachineEvent to all of the listeners on this Machine.
*
* @param type The type of event to fire.
*/
private void fireMachineEvent(int type) {
Vector toFireTo = null;
synchronized(listeners) {
toFireTo = (Vector)listeners.clone();
}
int numListeners = toFireTo.size();
for(int i = 0; i < numListeners; i++)
((MachineListener)toFireTo.elementAt(i)).
handleMachineEvent(new MachineEvent(this, type));
}
/**
* Sets the start state for this machine.
*
* @param state The new start state for this machine.
*/
public final void setStartState(State state) {
if(state == null)
throw new NullPointerException("Null start state");
synchronized(syncObject) {
if(this.startState != null)
this.startState.setStartStateFlag(false);
this.startState = state;
this.startState.setStartStateFlag(true);
}
}
/**
* Returns a handle to the starting state for this machine.
*
* @return The starting state for this machine or null if one is not set.
*/
public final State getStartState() {
State returnValue = null;
synchronized(syncObject) {
returnValue = startState;
}
return returnValue;
}
/**
* Forcibly sets the current state of this machine.
*
* NOTE: This is NOT recommended for use in general, but it is provided
* in case there is a need for it. No checking is done as to
* whether or not the state can be reached though valid transitions
* and any state listeners, and state IO is not performed.
*
* @param state The new current state.
*/
protected final void setCurrentState(State state) {
synchronized(syncObject) {
this.currentState = state;
}
}
/**
* Returns the current state of this machine.
*
* @return The current state of this machine.
*/
public final State getCurrentState() {
State returnValue = null;
synchronized(syncObject) {
returnValue = currentState;
}
return returnValue;
}
/**
* Takes input and passes it to the current State
. If the
* condition is met by one of the Condition
s of the
* State
, then the new current State
will be that
* returned by the input method of the present State
.
*
* @param condition The input to pass to the current State
.
* @throws UnhandledConditionException If the current State
* returns null
for its input method, then a condition
* has arisen that is not handled.
*/
public final void input(Object condition)
throws UnhandledConditionException {
synchronized(syncObject) {
if(currentState == null)
currentState = startState;
// find the new state
State newState = currentState.input(condition);
if(newState == null)
throw new UnhandledConditionException(currentState, condition);
Object stateData = currentState.exitState();
currentState = newState;
currentState.enterState(stateData);
}
}
/**
* Convenience method to handle the boolean primitive as an input
* condition.
*
* @param condition The value to input.
*/
public final void input(boolean condition)
throws UnhandledConditionException {
input(new Boolean(condition));
}
/**
* Convenience method to handle the byte primitive type as an input
* condition.
*
* @param condition The value to input.
*/
public final void input(byte condition)
throws UnhandledConditionException {
input(new Byte(condition));
}
/**
* Convience method to handle the char primitive type as an input
* condition.
*
* @param condition The value to input.
*/
public final void input(char condition)
throws UnhandledConditionException {
input(new Character(condition));
}
/**
* Convience method to handle the double primitive type as an input
* condition.
*
* @param condition The value to input.
*/
public final void input(double condition)
throws UnhandledConditionException {
input(new Double(condition));
}
/**
* Convience method to handle the float primitive type as an input
* condition.
*
* @param condition The value to input.
*/
public final void input(float condition)
throws UnhandledConditionException {
input(new Float(condition));
}
/**
* Convience method to handle the int primitive type as an input
* condition.
*
* @param condition The value to input.
*/
public final void input(int condition)
throws UnhandledConditionException {
input(new Integer(condition));
}
/**
* Convience method to handle the long primitive type as an input
* condition.
*
* @param condition The value to input.
*/
public final void input(long condition)
throws UnhandledConditionException {
input(new Long(condition));
}
/**
* Convience method to handle the Short primitive type as an input
* condition.
*
* @param condition The value to input.
*/
public final void input(short condition)
throws UnhandledConditionException {
input(new Short(condition));
}
/**
* Resets this machine so that its current State
is the
* start state. No state transitions will be fired. This is the same
* as calling reset(false, false)
.
*/
public final void reset() {
reset(false, false);
}
/**
* Resets this machine so that its current State
is the
* start state. If asTransition
is true
then
* the output of the current state (if it exists) will be input into
* the start state and the start state will be the new current state.
* If it is false
then the current state will simply be set
* to be the start state.
*
* @param asTransition If true
then the current state
* and the start state will act as if there is
* a transition between them.
* @param nullifyInput If true
then null will be fed into
* the start state instead of the output of the
* current state.
*/
public final void reset(boolean asTransition, boolean nullifyInput) {
synchronized(syncObject) {
if(asTransition) {
Object stateData = null;
if(currentState != null)
stateData = currentState.exitState();
currentState = startState;
if(nullifyInput)
stateData = null;
if(currentState != null)
currentState.enterState(stateData);
} else {
currentState = startState;
}
}
}
}