1 /* 2 * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.corba.se.impl.orbutil.fsm ; 27 28 import java.util.HashMap ; 29 import java.util.HashSet ; 30 import java.util.Set ; 31 import java.util.Iterator ; 32 33 import org.omg.CORBA.INTERNAL ; 34 35 import com.sun.corba.se.impl.orbutil.ORBUtility ; 36 37 import com.sun.corba.se.spi.orbutil.fsm.Input ; 38 import com.sun.corba.se.spi.orbutil.fsm.Guard ; 39 import com.sun.corba.se.spi.orbutil.fsm.Action ; 40 import com.sun.corba.se.spi.orbutil.fsm.ActionBase ; 41 import com.sun.corba.se.spi.orbutil.fsm.State ; 42 import com.sun.corba.se.spi.orbutil.fsm.StateEngine ; 43 import com.sun.corba.se.spi.orbutil.fsm.StateImpl ; 44 import com.sun.corba.se.spi.orbutil.fsm.FSM ; 45 import com.sun.corba.se.spi.orbutil.fsm.FSMImpl ; 46 47 import com.sun.corba.se.impl.orbutil.fsm.GuardedAction ; 48 49 /** 50 * Encodes the state transition function for a finite state machine. 51 * 52 * @author Ken Cavanaugh 53 */ 54 public class StateEngineImpl implements StateEngine 55 { 56 // An action that does nothing at all. 57 private static Action emptyAction = new ActionBase( "Empty" ) 58 { 59 public void doIt( FSM fsm, Input in ) 60 { 61 } 62 } ; 63 64 private boolean initializing ; 65 private Action defaultAction ; 66 67 public StateEngineImpl() 68 { 69 initializing = true ; 70 defaultAction = new ActionBase("Invalid Transition") 71 { 72 public void doIt( FSM fsm, Input in ) 73 { 74 throw new INTERNAL( 75 "Invalid transition attempted from " + 76 fsm.getState() + " under " + in ) ; 77 } 78 } ; 79 } 80 81 public StateEngine add( State oldState, Input input, Guard guard, Action action, 82 State newState ) throws IllegalArgumentException, 83 IllegalStateException 84 { 85 mustBeInitializing() ; 86 87 StateImpl oldStateImpl = (StateImpl)oldState ; 88 GuardedAction ga = new GuardedAction( guard, action, newState ) ; 89 oldStateImpl.addGuardedAction( input, ga ) ; 90 91 return this ; 92 } 93 94 public StateEngine add( State oldState, Input input, Action action, 95 State newState ) throws IllegalArgumentException, 96 IllegalStateException 97 { 98 mustBeInitializing() ; 99 100 StateImpl oldStateImpl = (StateImpl)oldState ; 101 GuardedAction ta = new GuardedAction( action, newState ) ; 102 oldStateImpl.addGuardedAction( input, ta ) ; 103 104 return this ; 105 } 106 107 public StateEngine setDefault( State oldState, Action action, State newState ) 108 throws IllegalArgumentException, IllegalStateException 109 { 110 mustBeInitializing() ; 111 112 StateImpl oldStateImpl = (StateImpl)oldState ; 113 oldStateImpl.setDefaultAction( action ) ; 114 oldStateImpl.setDefaultNextState( newState ) ; 115 116 return this ; 117 } 118 119 public StateEngine setDefault( State oldState, State newState ) 120 throws IllegalArgumentException, IllegalStateException 121 { 122 return setDefault( oldState, emptyAction, newState ) ; 123 } 124 125 public StateEngine setDefault( State oldState ) 126 throws IllegalArgumentException, IllegalStateException 127 { 128 return setDefault( oldState, oldState ) ; 129 } 130 131 public void done() throws IllegalStateException 132 { 133 mustBeInitializing() ; 134 135 // optimize FSM here if desired. For example, 136 // we could choose different strategies for implementing 137 // the state transition function based on the distribution 138 // of values for states and input labels. 139 140 initializing = false ; 141 } 142 143 public void setDefaultAction( Action act ) throws IllegalStateException 144 { 145 mustBeInitializing() ; 146 defaultAction = act ; 147 } 148 149 public void doIt( FSM fsm, Input in, boolean debug ) 150 { 151 // This method is present only for debugging. 152 // innerDoIt does the actual transition. 153 154 if (debug) 155 ORBUtility.dprint( this, "doIt enter: currentState = " + 156 fsm.getState() + " in = " + in ) ; 157 158 try { 159 innerDoIt( fsm, in, debug ) ; 160 } finally { 161 if (debug) 162 ORBUtility.dprint( this, "doIt exit" ) ; 163 } 164 } 165 166 private StateImpl getDefaultNextState( StateImpl currentState ) 167 { 168 // Use the currentState defaults if 169 // set, otherwise use the state engine default. 170 StateImpl nextState = (StateImpl)currentState.getDefaultNextState() ; 171 if (nextState == null) 172 // The state engine default never changes the state 173 nextState = currentState ; 174 175 return nextState ; 176 } 177 178 private Action getDefaultAction( StateImpl currentState ) 179 { 180 Action action = currentState.getDefaultAction() ; 181 if (action == null) 182 action = defaultAction ; 183 184 return action ; 185 } 186 187 private void innerDoIt( FSM fsm, Input in, boolean debug ) 188 { 189 if (debug) { 190 ORBUtility.dprint( this, "Calling innerDoIt with input " + in ) ; 191 } 192 193 // Locals needed for performing the state transition, once we determine 194 // the required transition. 195 StateImpl currentState = null ; 196 StateImpl nextState = null ; 197 Action action = null ; 198 199 // Do until no guard has deferred. 200 boolean deferral = false ; 201 do { 202 deferral = false ; // clear this after each deferral! 203 currentState = (StateImpl)fsm.getState() ; 204 nextState = getDefaultNextState( currentState ) ; 205 action = getDefaultAction( currentState ) ; 206 207 if (debug) { 208 ORBUtility.dprint( this, "currentState = " + currentState ) ; 209 ORBUtility.dprint( this, "in = " + in ) ; 210 ORBUtility.dprint( this, "default nextState = " + nextState ) ; 211 ORBUtility.dprint( this, "default action = " + action ) ; 212 } 213 214 Set gas = currentState.getGuardedActions(in) ; 215 if (gas != null) { 216 Iterator iter = gas.iterator() ; 217 218 // Search for a guard that is not DISABLED. 219 // All DISABLED means use defaults. 220 while (iter.hasNext()) { 221 GuardedAction ga = (GuardedAction)iter.next() ; 222 Guard.Result gr = ga.getGuard().evaluate( fsm, in ) ; 223 if (debug) 224 ORBUtility.dprint( this, 225 "doIt: evaluated " + ga + " with result " + gr ) ; 226 227 if (gr == Guard.Result.ENABLED) { 228 // ga has the next state and action. 229 nextState = (StateImpl)ga.getNextState() ; 230 action = ga.getAction() ; 231 if (debug) { 232 ORBUtility.dprint( this, "nextState = " + nextState ) ; 233 ORBUtility.dprint( this, "action = " + action ) ; 234 } 235 break ; 236 } else if (gr == Guard.Result.DEFERED) { 237 deferral = true ; 238 break ; 239 } 240 } 241 } 242 } while (deferral) ; 243 244 performStateTransition( fsm, in, nextState, action, debug ) ; 245 } 246 247 private void performStateTransition( FSM fsm, Input in, 248 StateImpl nextState, Action action, boolean debug ) 249 { 250 StateImpl currentState = (StateImpl)fsm.getState() ; 251 252 // Perform the state transition. Pre and post actions are only 253 // performed if the state changes (see UML hidden transitions). 254 255 boolean different = !currentState.equals( nextState ) ; 256 257 if (different) { 258 if (debug) 259 ORBUtility.dprint( this, 260 "doIt: executing postAction for state " + currentState ) ; 261 try { 262 currentState.postAction( fsm ) ; 263 } catch (Throwable thr) { 264 if (debug) 265 ORBUtility.dprint( this, 266 "doIt: postAction threw " + thr ) ; 267 268 if (thr instanceof ThreadDeath) 269 throw (ThreadDeath)thr ; 270 } 271 } 272 273 try { 274 // Note that action may be null in a transition, which simply 275 // means that no action is needed. Note that action.doIt may 276 // throw an exception, in which case the exception is 277 // propagated after making sure that the transition is properly 278 // completed. 279 if (action != null) 280 action.doIt( fsm, in ) ; 281 } finally { 282 if (different) { 283 if (debug) 284 ORBUtility.dprint( this, 285 "doIt: executing preAction for state " + nextState ) ; 286 287 try { 288 nextState.preAction( fsm ) ; 289 } catch (Throwable thr) { 290 if (debug) 291 ORBUtility.dprint( this, 292 "doIt: preAction threw " + thr ) ; 293 294 if (thr instanceof ThreadDeath) 295 throw (ThreadDeath)thr ; 296 } 297 298 ((FSMImpl)fsm).internalSetState( nextState ) ; 299 } 300 301 if (debug) 302 ORBUtility.dprint( this, "doIt: state is now " + nextState ) ; 303 } 304 } 305 306 public FSM makeFSM( State startState ) throws IllegalStateException 307 { 308 mustNotBeInitializing() ; 309 310 return new FSMImpl( this, startState ) ; 311 } 312 313 private void mustBeInitializing() throws IllegalStateException 314 { 315 if (!initializing) 316 throw new IllegalStateException( 317 "Invalid method call after initialization completed" ) ; 318 } 319 320 private void mustNotBeInitializing() throws IllegalStateException 321 { 322 if (initializing) 323 throw new IllegalStateException( 324 "Invalid method call before initialization completed" ) ; 325 } 326 } 327 328 // end of StateEngineImpl.java