Java/Collections Data Structure/State Machine

Материал из Java эксперт
Перейти к: навигация, поиск

The representation of a finite state machine

 
/*
 * 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);
  }
}