| /* |
| * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code 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 General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.sun.corba.se.impl.orbutil.fsm ; |
| |
| import java.util.HashMap ; |
| import java.util.HashSet ; |
| import java.util.Set ; |
| import java.util.Iterator ; |
| |
| import org.omg.CORBA.INTERNAL ; |
| |
| import com.sun.corba.se.impl.orbutil.ORBUtility ; |
| |
| import com.sun.corba.se.spi.orbutil.fsm.Input ; |
| import com.sun.corba.se.spi.orbutil.fsm.Guard ; |
| import com.sun.corba.se.spi.orbutil.fsm.Action ; |
| import com.sun.corba.se.spi.orbutil.fsm.ActionBase ; |
| import com.sun.corba.se.spi.orbutil.fsm.State ; |
| import com.sun.corba.se.spi.orbutil.fsm.StateEngine ; |
| import com.sun.corba.se.spi.orbutil.fsm.StateImpl ; |
| import com.sun.corba.se.spi.orbutil.fsm.FSM ; |
| import com.sun.corba.se.spi.orbutil.fsm.FSMImpl ; |
| |
| import com.sun.corba.se.impl.orbutil.fsm.GuardedAction ; |
| |
| /** |
| * Encodes the state transition function for a finite state machine. |
| * |
| * @author Ken Cavanaugh |
| */ |
| public class StateEngineImpl implements StateEngine |
| { |
| // An action that does nothing at all. |
| private static Action emptyAction = new ActionBase( "Empty" ) |
| { |
| public void doIt( FSM fsm, Input in ) |
| { |
| } |
| } ; |
| |
| private boolean initializing ; |
| private Action defaultAction ; |
| |
| public StateEngineImpl() |
| { |
| initializing = true ; |
| defaultAction = new ActionBase("Invalid Transition") |
| { |
| public void doIt( FSM fsm, Input in ) |
| { |
| throw new INTERNAL( |
| "Invalid transition attempted from " + |
| fsm.getState() + " under " + in ) ; |
| } |
| } ; |
| } |
| |
| public StateEngine add( State oldState, Input input, Guard guard, Action action, |
| State newState ) throws IllegalArgumentException, |
| IllegalStateException |
| { |
| mustBeInitializing() ; |
| |
| StateImpl oldStateImpl = (StateImpl)oldState ; |
| GuardedAction ga = new GuardedAction( guard, action, newState ) ; |
| oldStateImpl.addGuardedAction( input, ga ) ; |
| |
| return this ; |
| } |
| |
| public StateEngine add( State oldState, Input input, Action action, |
| State newState ) throws IllegalArgumentException, |
| IllegalStateException |
| { |
| mustBeInitializing() ; |
| |
| StateImpl oldStateImpl = (StateImpl)oldState ; |
| GuardedAction ta = new GuardedAction( action, newState ) ; |
| oldStateImpl.addGuardedAction( input, ta ) ; |
| |
| return this ; |
| } |
| |
| public StateEngine setDefault( State oldState, Action action, State newState ) |
| throws IllegalArgumentException, IllegalStateException |
| { |
| mustBeInitializing() ; |
| |
| StateImpl oldStateImpl = (StateImpl)oldState ; |
| oldStateImpl.setDefaultAction( action ) ; |
| oldStateImpl.setDefaultNextState( newState ) ; |
| |
| return this ; |
| } |
| |
| public StateEngine setDefault( State oldState, State newState ) |
| throws IllegalArgumentException, IllegalStateException |
| { |
| return setDefault( oldState, emptyAction, newState ) ; |
| } |
| |
| public StateEngine setDefault( State oldState ) |
| throws IllegalArgumentException, IllegalStateException |
| { |
| return setDefault( oldState, oldState ) ; |
| } |
| |
| public void done() throws IllegalStateException |
| { |
| mustBeInitializing() ; |
| |
| // optimize FSM here if desired. For example, |
| // we could choose different strategies for implementing |
| // the state transition function based on the distribution |
| // of values for states and input labels. |
| |
| initializing = false ; |
| } |
| |
| public void setDefaultAction( Action act ) throws IllegalStateException |
| { |
| mustBeInitializing() ; |
| defaultAction = act ; |
| } |
| |
| public void doIt( FSM fsm, Input in, boolean debug ) |
| { |
| // This method is present only for debugging. |
| // innerDoIt does the actual transition. |
| |
| if (debug) |
| ORBUtility.dprint( this, "doIt enter: currentState = " + |
| fsm.getState() + " in = " + in ) ; |
| |
| try { |
| innerDoIt( fsm, in, debug ) ; |
| } finally { |
| if (debug) |
| ORBUtility.dprint( this, "doIt exit" ) ; |
| } |
| } |
| |
| private StateImpl getDefaultNextState( StateImpl currentState ) |
| { |
| // Use the currentState defaults if |
| // set, otherwise use the state engine default. |
| StateImpl nextState = (StateImpl)currentState.getDefaultNextState() ; |
| if (nextState == null) |
| // The state engine default never changes the state |
| nextState = currentState ; |
| |
| return nextState ; |
| } |
| |
| private Action getDefaultAction( StateImpl currentState ) |
| { |
| Action action = currentState.getDefaultAction() ; |
| if (action == null) |
| action = defaultAction ; |
| |
| return action ; |
| } |
| |
| private void innerDoIt( FSM fsm, Input in, boolean debug ) |
| { |
| if (debug) { |
| ORBUtility.dprint( this, "Calling innerDoIt with input " + in ) ; |
| } |
| |
| // Locals needed for performing the state transition, once we determine |
| // the required transition. |
| StateImpl currentState = null ; |
| StateImpl nextState = null ; |
| Action action = null ; |
| |
| // Do until no guard has deferred. |
| boolean deferral = false ; |
| do { |
| deferral = false ; // clear this after each deferral! |
| currentState = (StateImpl)fsm.getState() ; |
| nextState = getDefaultNextState( currentState ) ; |
| action = getDefaultAction( currentState ) ; |
| |
| if (debug) { |
| ORBUtility.dprint( this, "currentState = " + currentState ) ; |
| ORBUtility.dprint( this, "in = " + in ) ; |
| ORBUtility.dprint( this, "default nextState = " + nextState ) ; |
| ORBUtility.dprint( this, "default action = " + action ) ; |
| } |
| |
| Set gas = currentState.getGuardedActions(in) ; |
| if (gas != null) { |
| Iterator iter = gas.iterator() ; |
| |
| // Search for a guard that is not DISABLED. |
| // All DISABLED means use defaults. |
| while (iter.hasNext()) { |
| GuardedAction ga = (GuardedAction)iter.next() ; |
| Guard.Result gr = ga.getGuard().evaluate( fsm, in ) ; |
| if (debug) |
| ORBUtility.dprint( this, |
| "doIt: evaluated " + ga + " with result " + gr ) ; |
| |
| if (gr == Guard.Result.ENABLED) { |
| // ga has the next state and action. |
| nextState = (StateImpl)ga.getNextState() ; |
| action = ga.getAction() ; |
| if (debug) { |
| ORBUtility.dprint( this, "nextState = " + nextState ) ; |
| ORBUtility.dprint( this, "action = " + action ) ; |
| } |
| break ; |
| } else if (gr == Guard.Result.DEFERED) { |
| deferral = true ; |
| break ; |
| } |
| } |
| } |
| } while (deferral) ; |
| |
| performStateTransition( fsm, in, nextState, action, debug ) ; |
| } |
| |
| private void performStateTransition( FSM fsm, Input in, |
| StateImpl nextState, Action action, boolean debug ) |
| { |
| StateImpl currentState = (StateImpl)fsm.getState() ; |
| |
| // Perform the state transition. Pre and post actions are only |
| // performed if the state changes (see UML hidden transitions). |
| |
| boolean different = !currentState.equals( nextState ) ; |
| |
| if (different) { |
| if (debug) |
| ORBUtility.dprint( this, |
| "doIt: executing postAction for state " + currentState ) ; |
| try { |
| currentState.postAction( fsm ) ; |
| } catch (Throwable thr) { |
| if (debug) |
| ORBUtility.dprint( this, |
| "doIt: postAction threw " + thr ) ; |
| |
| if (thr instanceof ThreadDeath) |
| throw (ThreadDeath)thr ; |
| } |
| } |
| |
| try { |
| // Note that action may be null in a transition, which simply |
| // means that no action is needed. Note that action.doIt may |
| // throw an exception, in which case the exception is |
| // propagated after making sure that the transition is properly |
| // completed. |
| if (action != null) |
| action.doIt( fsm, in ) ; |
| } finally { |
| if (different) { |
| if (debug) |
| ORBUtility.dprint( this, |
| "doIt: executing preAction for state " + nextState ) ; |
| |
| try { |
| nextState.preAction( fsm ) ; |
| } catch (Throwable thr) { |
| if (debug) |
| ORBUtility.dprint( this, |
| "doIt: preAction threw " + thr ) ; |
| |
| if (thr instanceof ThreadDeath) |
| throw (ThreadDeath)thr ; |
| } |
| |
| ((FSMImpl)fsm).internalSetState( nextState ) ; |
| } |
| |
| if (debug) |
| ORBUtility.dprint( this, "doIt: state is now " + nextState ) ; |
| } |
| } |
| |
| public FSM makeFSM( State startState ) throws IllegalStateException |
| { |
| mustNotBeInitializing() ; |
| |
| return new FSMImpl( this, startState ) ; |
| } |
| |
| private void mustBeInitializing() throws IllegalStateException |
| { |
| if (!initializing) |
| throw new IllegalStateException( |
| "Invalid method call after initialization completed" ) ; |
| } |
| |
| private void mustNotBeInitializing() throws IllegalStateException |
| { |
| if (initializing) |
| throw new IllegalStateException( |
| "Invalid method call before initialization completed" ) ; |
| } |
| } |
| |
| // end of StateEngineImpl.java |