StateMachine.java Source code

Java tutorial

Introduction

Here is the source code for StateMachine.java

Source

/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * The representation of a finite state machine.
 * 
 * @author Scott.Stark@jboss.org
 * @version $Revision: 2787 $
 */
@SuppressWarnings("unchecked")
public class StateMachine implements Cloneable {

    /** A description of the state machine */
    private String description;

    /** The set of states making up the state machine */
    private HashSet states;

    /** The starting state */
    private State startState;

    /** The current state of the state machine */
    private State currentState;

    /**
     * Create a state machine given its states and start state.
     * 
     * @param states -
     *          Set<State> for the state machine
     * @param startState -
     *          the starting state
     */
    public StateMachine(Set states, State startState) {
        this(states, startState, null);
    }

    /**
     * Create a state machine given its states and start state.
     * 
     * @param states -
     *          Set<State> for the state machine
     * @param startState -
     *          the starting state
     * @param description -
     *          an optional description of the state machine
     */
    public StateMachine(Set states, State startState, String description) {
        this.states = new HashSet(states);
        this.startState = startState;
        this.currentState = startState;
        this.description = description;
    }

    /**
     * Make a copy of the StateMachine maintaining the current state.
     * 
     * @return a copy of the StateMachine.
     */
    public Object clone() {
        StateMachine clone = new StateMachine(states, startState, description);
        clone.currentState = currentState;
        return clone;
    }

    /**
     * Get the state machine description.
     * 
     * @return an possibly null description.
     */
    public String getDescription() {
        return description;
    }

    /**
     * Get the current state of the state machine.
     * 
     * @return the current state.
     */
    public State getCurrentState() {
        return currentState;
    }

    /**
     * Get the start state of the state machine.
     * 
     * @return the start state.
     */
    public State getStartState() {
        return startState;
    }

    /**
     * Get the states of the state machine.
     * 
     * @return the machine states.
     */
    public Set getStates() {
        return states;
    }

    /**
     * Transition to the next state given the name of a valid transition.
     * 
     * @param actionName -
     *          the name of transition that is valid for the current state.
     * @return the next state
     * @throws IllegalTransitionException
     */
    public State nextState(String actionName) throws IllegalTransitionException {
        Transition t = currentState.getTransition(actionName);
        if (t == null) {
            String msg = "No transition for action: '" + actionName + "' from state: '" + currentState.getName()
                    + "'";
            throw new IllegalTransitionException(msg);
        }
        State nextState = t.getTarget();
        System.out.println("nextState(" + actionName + ") = " + nextState);
        currentState = nextState;
        return currentState;
    }

    /**
     * Reset the state machine back to the start state
     * 
     * @return the start state
     */
    public State reset() {
        this.currentState = startState;
        return currentState;
    }

    public String toString() {
        StringBuffer tmp = new StringBuffer("StateMachine[:\n");
        tmp.append("\tCurrentState: " + currentState.getName());
        Iterator i = states.iterator();
        while (i.hasNext()) {
            tmp.append('\n').append(i.next());
        }
        tmp.append(']');
        return tmp.toString();
    }
}

/*
 * JBoss, Home of Professional Open Source Copyright 2005, JBoss Inc., and
 * individual contributors as indicated by the @authors tag. See the
 * copyright.txt in the distribution for a full listing of individual
 * contributors.
 * 
 * This is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This software is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this software; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF
 * site: http://www.fsf.org.
 */

/**
 * The respresentation of a state in a state machine.
 * 
 * @author Scott.Stark@jboss.org
 * @version $Revision: 2787 $
 */
@SuppressWarnings("unchecked")
class State {
    /** The name of the state */
    private String name;

    /** HashMap<String, Transition> */
    private HashMap allowedTransitions = new HashMap();

    /** Arbitrary state data */
    private Object data;

    public State(String name) {
        this(name, null);
    }

    public State(String name, Map transitions) {
        this.name = name;
        if (transitions != null) {
            allowedTransitions.putAll(transitions);
        }
    }

    /**
     * Get the state name.
     * 
     * @return the name of the state.
     */
    public String getName() {
        return name;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    /**
     * An accept state is indicated by no transitions
     * 
     * @return true if this is an accept state, false otherwise.
     */
    public boolean isAcceptState() {
        return allowedTransitions.size() == 0;
    }

    /**
     * Add a transition to the allowed transition map.
     * 
     * @param transition
     * @return this to allow chained addTransition calls
     */
    public State addTransition(Transition transition) {
        allowedTransitions.put(transition.getName(), transition);
        return this;
    }

    /**
     * Lookup an allowed transition given its name.
     * 
     * @param name -
     *          the name of a valid transition from this state.
     * @return the valid transition if it exists, null otherwise.
     */
    public Transition getTransition(String name) {
        Transition t = (Transition) allowedTransitions.get(name);
        return t;
    }

    /**
     * Get the Map<String, Transition> of allowed transitions for this state.
     * 
     * @return the allowed transitions map.
     */
    public Map getTransitions() {
        return allowedTransitions;
    }

    public String toString() {
        StringBuffer tmp = new StringBuffer("State(name=");
        tmp.append(name);
        Iterator i = allowedTransitions.entrySet().iterator();
        while (i.hasNext()) {
            Map.Entry e = (Map.Entry) i.next();
            tmp.append("\n\t on: ");
            tmp.append(e.getKey());
            Transition t = (Transition) e.getValue();
            tmp.append(" go to: ");
            tmp.append(t.getTarget().getName());
        }
        tmp.append(')');
        return tmp.toString();
    }
}

/*
 * JBoss, Home of Professional Open Source Copyright 2005, JBoss Inc., and
 * individual contributors as indicated by the @authors tag. See the
 * copyright.txt in the distribution for a full listing of individual
 * contributors.
 * 
 * This is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This software is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this software; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF
 * site: http://www.fsf.org.
 */

/**
 * A representation of a transition from a state to another state.
 * 
 * @author Scott.Stark@jboss.org
 * @version $Revision: 1958 $
 */
class Transition {
    private String name;

    private State target;

    public Transition(String name, State target) {
        this.name = name;
        this.target = target;
    }

    public String getName() {
        return name;
    }

    public State getTarget() {
        return target;
    }
}

/*
 * JBoss, Home of Professional Open Source Copyright 2005, JBoss Inc., and
 * individual contributors as indicated by the @authors tag. See the
 * copyright.txt in the distribution for a full listing of individual
 * contributors.
 * 
 * This is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This software is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this software; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF
 * site: http://www.fsf.org.
 */

/**
 * An exception thrown when an invalid transition is attempted from a state.
 * 
 * @author Scott.Stark@jboss.org
 * @version $Revision: 2800 $
 */
class IllegalTransitionException extends Exception {
    /** The serialVersionUID */
    private static final long serialVersionUID = -3392564168782896452L;

    public IllegalTransitionException(String msg) {
        super(msg);
    }
}