CompositeState.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. #region --------------- Copyright Dresser Wayne Pignone -------------
  2. /*
  3. * $Log: /Wrk/WayneLibraries/Wrk/StateEngine/CompositeState.cs $
  4. *
  5. * 7 08-03-25 14:15 Mattias.larsson
  6. * Clean-up.
  7. *
  8. * 6 08-02-26 14:06 Mattias.larsson
  9. * Renamed stateName to factoryName.
  10. *
  11. * 5 07-08-15 15:27 roger.månsson
  12. * Added SetDebugLogger method.
  13. *
  14. * 4 07-08-07 8:26 Mattias.larsson
  15. *
  16. * 3 07-03-02 13:19 roger.månsson
  17. */
  18. #endregion
  19. #region Old file header
  20. /*===============================================================================
  21. * CompositeState
  22. *
  23. * Change history
  24. * When Who Comment
  25. * ---------- ------ ------------------------------------
  26. * 2006-07-17 RMa Major updates, Changed state machine and event handling.
  27. * 2006-05-09 RMa Implemented the dispose handling.
  28. * 2006-03-01 RMa FXCop updates: CreateStateMachine is not virtual anymore.
  29. * 2006-02-03 RMa FXCop updates: Made constuctor protected + misc.
  30. * 2006-01-27 RMa Removed interface Event. Use Event class instead.
  31. * 2006-01-05 RMa Added the internal function LookupState
  32. * 2005-12-14 RMa Changed so Internal_Enter is called by the state machine, so we are sure that
  33. * the internal stuff gets called ,if the user forgets to call base.Enter()....
  34. * 2005-12-09 RMa Fixed so the state entry always is sent into a composite state machine.
  35. * 2005-12-05 RMa This header added.
  36. *
  37. ---------------------------------------------------------------------------------*/
  38. #endregion
  39. using System;
  40. using System.Linq;
  41. using Wayne.Lib.Log;
  42. namespace Wayne.Lib.StateEngine
  43. {
  44. /// <summary>
  45. /// Composite state is an abstract class that should be overriden to
  46. /// create a state that within itself have a state machine with sub states.
  47. /// When creating the composite state, a message handling thread should be sent
  48. /// in to the composite state constructor. It can either be a new thread if the
  49. /// composite state machine should run in a separate thread , or the thread of the
  50. /// parent state machine if the machine should run in the same thread.
  51. /// </summary>
  52. abstract public class CompositeState : State
  53. {
  54. #region Fields
  55. private StateMachine stateMachine;
  56. private bool disposed;
  57. #endregion
  58. #region Construction
  59. /// <summary>
  60. /// Initializes a new instance of a composite state.
  61. /// </summary>
  62. protected CompositeState()
  63. {
  64. stateMachine = new CompositeStateMachine(this);
  65. }
  66. /// <summary>
  67. /// Destructor
  68. /// </summary>
  69. ~CompositeState()
  70. {
  71. Dispose(false);
  72. }
  73. #endregion
  74. #region Methods
  75. /// <summary>
  76. /// Handles an incoming event.
  77. /// </summary>
  78. /// <param name="stateEngineEvent">Event that is received.</param>
  79. /// <param name="transition">Perform a transaction by assigning a transition object to this ref parameter.</param>
  80. protected sealed override void HandleEvent(StateEngineEvent stateEngineEvent, ref Transition transition)
  81. {
  82. BeforeHandleEvent(stateEngineEvent, ref transition);
  83. if (!stateEngineEvent.Handled)
  84. stateMachine.HandleEvent(stateEngineEvent, ref transition);
  85. if (!stateEngineEvent.Handled)
  86. UnhandledEvent(stateEngineEvent, ref transition);
  87. }
  88. /// <summary>
  89. /// Method that can be overriden in descendant classes, so events can be handed before they are sent to the
  90. /// state machine.
  91. /// </summary>
  92. /// <param name="stateEngineEvent"></param>
  93. /// <param name="transition">Perform a transaction by assigning a transition object to this ref parameter.</param>
  94. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "1#")]
  95. public virtual void BeforeHandleEvent(StateEngineEvent stateEngineEvent, ref Transition transition)
  96. {
  97. }
  98. /// <summary>
  99. /// Method that can be overriden if wanting to handle events that not has been handled in the composite state machine.
  100. /// </summary>
  101. /// <param name="stateEngineEvent"></param>
  102. /// <param name="transition">Perform a transaction by assigning a transition object to this ref parameter.</param>
  103. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "1#")]
  104. public virtual void UnhandledEvent(StateEngineEvent stateEngineEvent, ref Transition transition)
  105. {
  106. }
  107. #endregion
  108. #region Internal Methods
  109. internal override void PerformEnter(StateEntry entry, ref Transition transition)
  110. {
  111. base.PerformEnter(entry, ref transition);
  112. if (!stateMachine.Initialized)
  113. this.Initialize();
  114. //If base did not result in any transition,
  115. if (transition == null)
  116. {
  117. stateMachine.EnterState(entry, ref transition);
  118. if (transition != null)
  119. stateMachine.HandleTransition(ref transition);
  120. }
  121. }
  122. internal override void PerformExit()
  123. {
  124. base.PerformExit();
  125. stateMachine.ExitState();
  126. }
  127. /// <summary>
  128. /// Initializes and creates the states of the composite state engine.
  129. /// </summary>
  130. internal void Initialize()
  131. {
  132. if (!stateMachine.Initialized)
  133. stateMachine.Initialize();
  134. }
  135. /// <summary>
  136. /// This function is used to locate a specific state in the state machine.
  137. ///
  138. /// The composite state checks first if its own FactoryName matches the name,
  139. /// if not it calls each created state subsequently.
  140. /// </summary>
  141. /// <param name="factoryName">The name of the state that should be looked up.</param>
  142. /// <returns>True if the state is or contains a state with this name.</returns>
  143. internal override bool LookupState(string factoryName)
  144. {
  145. if (base.LookupState(factoryName))
  146. return true;
  147. foreach (State state in StateMachine.CreatedStates)
  148. {
  149. if (state.LookupState(factoryName))
  150. return true;
  151. }
  152. return false;
  153. }
  154. /// <summary>
  155. /// Internal dispose method.
  156. /// </summary>
  157. /// <param name="disposing"></param>
  158. protected override void Dispose(bool disposing)
  159. {
  160. try
  161. {
  162. if (!disposed)
  163. {
  164. disposed = true;
  165. if (disposing)
  166. stateMachine.Dispose();
  167. }
  168. }
  169. finally
  170. {
  171. base.Dispose(disposing);
  172. }
  173. }
  174. #endregion
  175. #region Properties
  176. /// <summary>
  177. /// Returns the state machine that is used with the Composite state.
  178. /// </summary>
  179. public StateMachine StateMachine
  180. {
  181. get { return stateMachine; }
  182. }
  183. /// <summary>
  184. /// Set the parent state machine for the state.
  185. /// </summary>
  186. internal override void SetParentStateMachine(StateMachine parentStateMachine)
  187. {
  188. base.SetParentStateMachine(parentStateMachine);
  189. this.stateMachine.ParentStateMachine = parentStateMachine;
  190. }
  191. /// <summary>
  192. /// Set the debug logger for the composite state, and assign it on to the state machine.
  193. /// </summary>
  194. /// <param name="debugLogger"></param>
  195. /// <param name="logCategory"></param>
  196. internal override void SetDebugLogger(IDebugLogger debugLogger, object logCategory)
  197. {
  198. base.SetDebugLogger(debugLogger, logCategory);
  199. this.stateMachine.SetDebugLogger(debugLogger, logCategory);
  200. }
  201. public override string Name
  202. {
  203. get { return GetType().Namespace.Split('.').LastOrDefault() ?? base.Name; }
  204. }
  205. #endregion
  206. }
  207. }