package jsetool.data; import java.io.Serializable; import java.util.*; /** * @author Mike Lawson * * @since Oct 20, 2004 * * The ExplorationState class represents an explored state generated from the * two communication finite state machines.
*
* It is composed of the current state and communication channel for both machine 1 and 2 * * */ public class ExplorationState implements Serializable { /** For now, we'll only support two CFSMs */ protected ExplorationStateContainer[] machines; /** The states that are next after this one. */ protected Vector nextStates = new Vector(); /** True if the state has been full explored already. */ protected boolean explored = false; /** Indicator of a deadlock state. */ protected boolean stateIsDeadlocked = false; /** Indicator of an unspecified reception state. */ protected boolean stateIsUnspecifiedReception = false; /** An optional attribute not used internally but can be used by a rendering engine to help itself.*/ protected Object associatedAttribute = null; protected static HashMap knownExplorationStates = new HashMap(); protected static int numberOfExplorationStatesCreated = 0; /** * An inner class that allow us to store both a next state and a * descriptive label for the transition. * * @author Mike Lawson * * @since Oct 23, 2004 * */ public class NextStateContainer implements Serializable { private ExplorationState es; private String transitionLabel; /** * Constructs a new NextStateContainer * @param es the next exploration state * @param transitionLabel */ public NextStateContainer(ExplorationState es, String transitionLabel) { this.es = es; this.transitionLabel = transitionLabel; } /** * Gets the exploration state * @return ExplorationState */ public ExplorationState getExplorationState() { return es; } /** * Gets the transition label * @return String */ public String getTransitionLabel() { return transitionLabel; } } // inner class NextStateContainer // // factory methods // /** * Factories an empty (m1.initial, m2.initial, E, E) state * @param m1 Machine 1 * @param m2 Machine 2 * @return ExplorationState */ public static ExplorationState emptyState(MachineState m1, MachineState m2) { ExplorationState es = new ExplorationState(m1, m2); knownExplorationStates.put(""+es.hashCode(), es); return es; } /** * Factories a new ExlorationState based on the given state, modifying M1. * M1 will be set to a new MachineState, and if a new message is given, * the message will be added to the machines communication channel. * * @param stateToExplore The original state being explored on which the new state will be based * @param target The new target for M1 * @param message Optional and may be null, the message that is to be added to m1's channel. * @return ExplorationState */ public static ExplorationState newStateForM1(ExplorationState stateToExplore, MachineState target, String message) { ExplorationState newState = new ExplorationState(stateToExplore); // Set the new state's new machine state to where the transition took us. newState.getMachine1().setMachineState(target); // Add the message to machine1's communication channel if (message != null) { newState.getMachine1().appendMessage(message); } // look in known states, if we already know about this newly created // state, return the FOUND state, if not, add this new state and return it. ExplorationState foundState = lookForState(newState); if (foundState == null) { knownExplorationStates.put("" + newState.hashCode(), newState); return newState; } else { return foundState; } } /** * Factories a new ExlorationState based on the given state, modifying M2. * M2 will be set to a new MachineState, and if a new message is given, * the message will be added to the machines communication channel. * * @param stateToExplore The original state being explored on which the new state will be based * @param target The new target for M2 * @param message Optional and may be null, the message that is to be added to m2's channel. * @return ExplorationState */ public static ExplorationState newStateForM2(ExplorationState stateToExplore, MachineState target, String message) { ExplorationState newState = new ExplorationState(stateToExplore); // Set the new state's new machine state to where the transition took us. newState.getMachine2().setMachineState(target); // Add the message to machine1's communication channel if (message != null) { newState.getMachine2().appendMessage(message); } // look in known states, if we already know about this newly created // state, return the FOUND state, if not, add this new state and return it. ExplorationState foundState = lookForState(newState); if (foundState == null) { knownExplorationStates.put("" + newState.hashCode(), newState); return newState; } else { return foundState; } } /** * Looks for the given state in the set of known states, * returns the FOUND state if found, null if not found. * @param s The state to see if we already have. * @return ExplorationState the FOUND state if found, null if not found. */ private static ExplorationState lookForState(ExplorationState s) { ExplorationState es = (ExplorationState)knownExplorationStates.get(""+s.hashCode()); return es; } /** * Default constructor * */ public ExplorationState() { } /** * Creates a new, deep copy of this object, except that the nextStates * attribute is left empty. * * @param other */ public ExplorationState(ExplorationState other) { machines = new ExplorationStateContainer[2]; // Clone the other's state containers. machines[0] = new ExplorationStateContainer(other.getMachine1()); machines[1] = new ExplorationStateContainer(other.getMachine2()); } /** * Constructs an ExplorationState with the given MachineStates. The * communication channels for both machines will be initialized as empty. * * @param m1 * the first machine state * @param m2 * the second machine state. */ public ExplorationState(MachineState m1, MachineState m2) { machines = new ExplorationStateContainer[2]; machines[0] = new ExplorationStateContainer(); machines[1] = new ExplorationStateContainer(); machines[0].setMachineState(m1); machines[1].setMachineState(m2); } /** * Return true if the given object is equal to this object. Equality is said * to be true if the states of both objects match plus all the channels are * exactly the same. * * @param obj * the other object to compare * @return boolean */ public boolean equals(Object obj) { if (!(obj instanceof ExplorationState)) { return false; } ExplorationState es = (ExplorationState) obj; return getMachine1().equals(es.getMachine1()) && getMachine2().equals(es.getMachine2()); } /** * Returns a hash code value for the object. This method is supported for the * benefit of hashtables such as those provided by * java.util.Hashtable. * * @return a hash code value for this object. */ public int hashCode() { int cornedBeef = 37; cornedBeef ^= getMachine1().hashCode(); cornedBeef ^= 37 * getMachine2().hashCode(); return cornedBeef; } /** * Prints the string representation of this object in the 4-tuple format * defined in class: (s1, s2, c1, c2) * * @return String */ public String toString() { String ret = "(" + machines[0].getMachineState() + "," + machines[1].getMachineState() + "," + machines[0].getCommunicationChannel() + "," + machines[1].getCommunicationChannel() + ")"; return ret; } /** * Returns the object associated with machine 1 * * @return Returns the machine1CommunicationChannel. */ public ExplorationStateContainer getMachine1() { return machines[0]; } /** * Returns the object associated with machine 2 * * @return Returns the machine1CommunicationChannel. */ public ExplorationStateContainer getMachine2() { return machines[1]; } /** * Adds a new next state to this ExplorationState * @param es The new ExplorationState discovered * @param transitionLabel A descriptive label (e.g. m1: -r) */ public void addNextState(ExplorationState es, String transitionLabel) { NextStateContainer nsc = new NextStateContainer(es, transitionLabel); nextStates.add(nsc); } /** * Returns the number of next states * @return int The number of next states. */ public int getNumberOfNextStates() { return nextStates.size(); } /** * Returns an iterator over the next states. * @return Iterator */ public Iterator nextStateIterator() { return nextStates.iterator(); } /** * @return Returns the stateIsDeadlocked. */ public boolean isStateIsDeadlocked() { return stateIsDeadlocked; } /** * Sets this state to deadlocked. */ public void setStateIsDeadlocked() { this.stateIsDeadlocked = true; } /** * @return Returns the stateIsUnspecifiedReception. */ public boolean isStateIsUnspecifiedReception() { return stateIsUnspecifiedReception; } /** * Sets this state to an unspecified reception */ public void setStateIsUnspecifiedReception() { this.stateIsUnspecifiedReception = true; } /** * Sets this state as having been explored. */ public void setExplored() { explored = true; } /** * @return Returns the explored. */ public boolean isExplored() { return explored; } /** * @return Returns the associatedAttribute. */ public Object getAssociatedAttribute() { return associatedAttribute; } /** * @param associatedAttribute The associatedAttribute to set. */ public void setAssociatedAttribute(Object associatedAttribute) { this.associatedAttribute = associatedAttribute; } /** * */ public static void resetKnownStates() { knownExplorationStates = new HashMap(); } }