1. /*
  2. * @(#)StateEngineImpl.java 1.20 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.corba.se.impl.orbutil.fsm ;
  8. import java.util.HashMap ;
  9. import java.util.HashSet ;
  10. import java.util.Set ;
  11. import java.util.Iterator ;
  12. import org.omg.CORBA.INTERNAL ;
  13. import com.sun.corba.se.impl.orbutil.ORBUtility ;
  14. import com.sun.corba.se.spi.orbutil.fsm.Input ;
  15. import com.sun.corba.se.spi.orbutil.fsm.Guard ;
  16. import com.sun.corba.se.spi.orbutil.fsm.Action ;
  17. import com.sun.corba.se.spi.orbutil.fsm.ActionBase ;
  18. import com.sun.corba.se.spi.orbutil.fsm.State ;
  19. import com.sun.corba.se.spi.orbutil.fsm.StateEngine ;
  20. import com.sun.corba.se.spi.orbutil.fsm.StateImpl ;
  21. import com.sun.corba.se.spi.orbutil.fsm.FSM ;
  22. import com.sun.corba.se.spi.orbutil.fsm.FSMImpl ;
  23. import com.sun.corba.se.impl.orbutil.fsm.GuardedAction ;
  24. /**
  25. * Encodes the state transition function for a finite state machine.
  26. *
  27. * @author Ken Cavanaugh
  28. */
  29. public class StateEngineImpl implements StateEngine
  30. {
  31. // An action that does nothing at all.
  32. private static Action emptyAction = new ActionBase( "Empty" )
  33. {
  34. public void doIt( FSM fsm, Input in )
  35. {
  36. }
  37. } ;
  38. private boolean initializing ;
  39. private Action defaultAction ;
  40. public StateEngineImpl()
  41. {
  42. initializing = true ;
  43. defaultAction = new ActionBase("Invalid Transition")
  44. {
  45. public void doIt( FSM fsm, Input in )
  46. {
  47. throw new INTERNAL(
  48. "Invalid transition attempted from " +
  49. fsm.getState() + " under " + in ) ;
  50. }
  51. } ;
  52. }
  53. public StateEngine add( State oldState, Input input, Guard guard, Action action,
  54. State newState ) throws IllegalArgumentException,
  55. IllegalStateException
  56. {
  57. mustBeInitializing() ;
  58. StateImpl oldStateImpl = (StateImpl)oldState ;
  59. GuardedAction ga = new GuardedAction( guard, action, newState ) ;
  60. oldStateImpl.addGuardedAction( input, ga ) ;
  61. return this ;
  62. }
  63. public StateEngine add( State oldState, Input input, Action action,
  64. State newState ) throws IllegalArgumentException,
  65. IllegalStateException
  66. {
  67. mustBeInitializing() ;
  68. StateImpl oldStateImpl = (StateImpl)oldState ;
  69. GuardedAction ta = new GuardedAction( action, newState ) ;
  70. oldStateImpl.addGuardedAction( input, ta ) ;
  71. return this ;
  72. }
  73. public StateEngine setDefault( State oldState, Action action, State newState )
  74. throws IllegalArgumentException, IllegalStateException
  75. {
  76. mustBeInitializing() ;
  77. StateImpl oldStateImpl = (StateImpl)oldState ;
  78. oldStateImpl.setDefaultAction( action ) ;
  79. oldStateImpl.setDefaultNextState( newState ) ;
  80. return this ;
  81. }
  82. public StateEngine setDefault( State oldState, State newState )
  83. throws IllegalArgumentException, IllegalStateException
  84. {
  85. return setDefault( oldState, emptyAction, newState ) ;
  86. }
  87. public StateEngine setDefault( State oldState )
  88. throws IllegalArgumentException, IllegalStateException
  89. {
  90. return setDefault( oldState, oldState ) ;
  91. }
  92. public void done() throws IllegalStateException
  93. {
  94. mustBeInitializing() ;
  95. // optimize FSM here if desired. For example,
  96. // we could choose different strategies for implementing
  97. // the state transition function based on the distribution
  98. // of values for states and input labels.
  99. initializing = false ;
  100. }
  101. public void setDefaultAction( Action act ) throws IllegalStateException
  102. {
  103. mustBeInitializing() ;
  104. defaultAction = act ;
  105. }
  106. public void doIt( FSM fsm, Input in, boolean debug )
  107. {
  108. // This method is present only for debugging.
  109. // innerDoIt does the actual transition.
  110. if (debug)
  111. ORBUtility.dprint( this, "doIt enter: currentState = " +
  112. fsm.getState() + " in = " + in ) ;
  113. try {
  114. innerDoIt( fsm, in, debug ) ;
  115. } finally {
  116. if (debug)
  117. ORBUtility.dprint( this, "doIt exit" ) ;
  118. }
  119. }
  120. private StateImpl getDefaultNextState( StateImpl currentState )
  121. {
  122. // Use the currentState defaults if
  123. // set, otherwise use the state engine default.
  124. StateImpl nextState = (StateImpl)currentState.getDefaultNextState() ;
  125. if (nextState == null)
  126. // The state engine default never changes the state
  127. nextState = currentState ;
  128. return nextState ;
  129. }
  130. private Action getDefaultAction( StateImpl currentState )
  131. {
  132. Action action = currentState.getDefaultAction() ;
  133. if (action == null)
  134. action = defaultAction ;
  135. return action ;
  136. }
  137. private void innerDoIt( FSM fsm, Input in, boolean debug )
  138. {
  139. if (debug) {
  140. ORBUtility.dprint( this, "Calling innerDoIt with input " + in ) ;
  141. }
  142. // Locals needed for performing the state transition, once we determine
  143. // the required transition.
  144. StateImpl currentState = null ;
  145. StateImpl nextState = null ;
  146. Action action = null ;
  147. // Do until no guard has deferred.
  148. boolean deferral = false ;
  149. do {
  150. deferral = false ; // clear this after each deferral!
  151. currentState = (StateImpl)fsm.getState() ;
  152. nextState = getDefaultNextState( currentState ) ;
  153. action = getDefaultAction( currentState ) ;
  154. if (debug) {
  155. ORBUtility.dprint( this, "currentState = " + currentState ) ;
  156. ORBUtility.dprint( this, "in = " + in ) ;
  157. ORBUtility.dprint( this, "default nextState = " + nextState ) ;
  158. ORBUtility.dprint( this, "default action = " + action ) ;
  159. }
  160. Set gas = currentState.getGuardedActions(in) ;
  161. if (gas != null) {
  162. Iterator iter = gas.iterator() ;
  163. // Search for a guard that is not DISABLED.
  164. // All DISABLED means use defaults.
  165. while (iter.hasNext()) {
  166. GuardedAction ga = (GuardedAction)iter.next() ;
  167. Guard.Result gr = ga.getGuard().evaluate( fsm, in ) ;
  168. if (debug)
  169. ORBUtility.dprint( this,
  170. "doIt: evaluated " + ga + " with result " + gr ) ;
  171. if (gr == Guard.Result.ENABLED) {
  172. // ga has the next state and action.
  173. nextState = (StateImpl)ga.getNextState() ;
  174. action = ga.getAction() ;
  175. if (debug) {
  176. ORBUtility.dprint( this, "nextState = " + nextState ) ;
  177. ORBUtility.dprint( this, "action = " + action ) ;
  178. }
  179. break ;
  180. } else if (gr == Guard.Result.DEFERED) {
  181. deferral = true ;
  182. break ;
  183. }
  184. }
  185. }
  186. } while (deferral) ;
  187. performStateTransition( fsm, in, nextState, action, debug ) ;
  188. }
  189. private void performStateTransition( FSM fsm, Input in,
  190. StateImpl nextState, Action action, boolean debug )
  191. {
  192. StateImpl currentState = (StateImpl)fsm.getState() ;
  193. // Perform the state transition. Pre and post actions are only
  194. // performed if the state changes (see UML hidden transitions).
  195. boolean different = !currentState.equals( nextState ) ;
  196. if (different) {
  197. if (debug)
  198. ORBUtility.dprint( this,
  199. "doIt: executing postAction for state " + currentState ) ;
  200. try {
  201. currentState.postAction( fsm ) ;
  202. } catch (Throwable thr) {
  203. if (debug)
  204. ORBUtility.dprint( this,
  205. "doIt: postAction threw " + thr ) ;
  206. if (thr instanceof ThreadDeath)
  207. throw (ThreadDeath)thr ;
  208. }
  209. }
  210. try {
  211. // Note that action may be null in a transition, which simply
  212. // means that no action is needed. Note that action.doIt may
  213. // throw an exception, in which case the exception is
  214. // propagated after making sure that the transition is properly
  215. // completed.
  216. if (action != null)
  217. action.doIt( fsm, in ) ;
  218. } finally {
  219. if (different) {
  220. if (debug)
  221. ORBUtility.dprint( this,
  222. "doIt: executing preAction for state " + nextState ) ;
  223. try {
  224. nextState.preAction( fsm ) ;
  225. } catch (Throwable thr) {
  226. if (debug)
  227. ORBUtility.dprint( this,
  228. "doIt: preAction threw " + thr ) ;
  229. if (thr instanceof ThreadDeath)
  230. throw (ThreadDeath)thr ;
  231. }
  232. ((FSMImpl)fsm).internalSetState( nextState ) ;
  233. }
  234. if (debug)
  235. ORBUtility.dprint( this, "doIt: state is now " + nextState ) ;
  236. }
  237. }
  238. public FSM makeFSM( State startState ) throws IllegalStateException
  239. {
  240. mustNotBeInitializing() ;
  241. return new FSMImpl( this, startState ) ;
  242. }
  243. private void mustBeInitializing() throws IllegalStateException
  244. {
  245. if (!initializing)
  246. throw new IllegalStateException(
  247. "Invalid method call after initialization completed" ) ;
  248. }
  249. private void mustNotBeInitializing() throws IllegalStateException
  250. {
  251. if (initializing)
  252. throw new IllegalStateException(
  253. "Invalid method call before initialization completed" ) ;
  254. }
  255. }
  256. // end of StateEngineImpl.java