/* * 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 org.jboss.com.sun.corba.se.impl.orbutil.fsm; import java.util.Iterator; import java.util.Set; import org.jboss.com.sun.corba.se.impl.orbutil.ORBUtility; import org.jboss.com.sun.corba.se.spi.orbutil.fsm.Action; import org.jboss.com.sun.corba.se.spi.orbutil.fsm.ActionBase; import org.jboss.com.sun.corba.se.spi.orbutil.fsm.FSM; import org.jboss.com.sun.corba.se.spi.orbutil.fsm.FSMImpl; import org.jboss.com.sun.corba.se.spi.orbutil.fsm.Guard; import org.jboss.com.sun.corba.se.spi.orbutil.fsm.Input; import org.jboss.com.sun.corba.se.spi.orbutil.fsm.State; import org.jboss.com.sun.corba.se.spi.orbutil.fsm.StateEngine; import org.jboss.com.sun.corba.se.spi.orbutil.fsm.StateImpl; import org.omg.CORBA.INTERNAL; /** * 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<GuardedAction> gas = currentState.getGuardedActions(in); if (gas != null) { Iterator<GuardedAction> iter = gas.iterator(); // Search for a guard that is not DISABLED. // All DISABLED means use defaults. while (iter.hasNext()) { GuardedAction ga = 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