private void ExecuteTransition(Transition transition) { // Default checking, if this is a valid transaction if (this.CurrentState.StateName != transition.SourceStateName) { string message = string.Format("Transition has wrong source state {0}, when system is in {1}", transition.SourceStateName, this.CurrentState.StateName); this.RaiseStateMachineSystemEvent("State machine: Default guard execute transition.", message); return; } if (!this.StateList.ContainsKey(transition.TargetStateName)) { string message = string.Format("Transition has wrong target state {0}, when system is in {1}. State not in global State List", transition.SourceStateName, this.CurrentState.StateName); this.RaiseStateMachineSystemEvent("State machine: Default guard execute transition.", message); return; } // Self transition - Just do the transition without executing exit, entry actions or guards if (transition.SourceStateName == transition.TargetStateName) { transition.TransitionActionList.ForEach(t => t.Execute()); return; // Important: return directly from self transition } // Run all exit actions of the old state this.CurrentState.ExitActions.ForEach(a => a.Execute()); // Run all guards of the transition transition.GuardList.ForEach(g => g.Execute()); string info = transition.GuardList.Count + " guard actions executed!"; this.RaiseStateMachineSystemEvent("State machine: ExcuteTransition", info); // Run all actions of the transition transition.TransitionActionList.ForEach(t => t.Execute()); //////////////// // State change //////////////// info = transition.TransitionActionList.Count + " transition actions executed."; this.RaiseStateMachineSystemEvent("State machine: Begin state change.", info); // First resolve the target state with the help of its name var targetState = this.GetStateFromStateList(transition.TargetStateName); // Transition succesfsul - Change state this.PreviousState = this.CurrentState; this.CurrentState = targetState; // run all entry actions of the new state foreach (var entryAction in this.CurrentState.EntryActions) { entryAction.Execute(); } this.RaiseStateMachineSystemEvent("State machine: State change completed successfully.", "Previous state: " + this.PreviousState.StateName + " - New state = " + this.CurrentState.StateName); }
/// <summary> /// Build telephone state configuration /// </summary> private void BuildConfig() { // Transitions and actions #region preparation of transitions and actions TelephoneActivities = new TelephoneActivities(); // create actions and map action methods into the corresponding action object // Device actions var actionBellRings = new StateMachineAction("ActionBellRings", this.TelephoneActivities.ActionBellRings); var actionBellSilent = new StateMachineAction("ActionBellSilent", this.TelephoneActivities.ActionBellSilent); var actionLineOff = new StateMachineAction("ActionLineOff", this.TelephoneActivities.ActionLineOff); var actionLineActive = new StateMachineAction("ActionLineActive", this.TelephoneActivities.ActionLineActive); // View Actions var actionViewPhoneRings = new StateMachineAction("ActionViewPhoneRings", this.TelephoneActivities.ActionViewPhoneRings); var actionViewPhoneIdle = new StateMachineAction("ActionViewPhoneIdle", this.TelephoneActivities.ActionViewPhoneIdle); var actionViewTalking = new StateMachineAction("ActionViewTalking", this.TelephoneActivities.ActionViewTalking); // Error Actions var actionViewErrorPhoneRings = new StateMachineAction("ActionViewErrorPhoneRings", TelephoneActivities.ActionErrorPhoneRings); // Create transitions and corresponding triggers, states need to be added var emptyList = new List<StateMachineAction>(); // to avoid null reference exceptions, use an empty list // transition IncomingCall var IncomingCallActions = new List<StateMachineAction>(); IncomingCallActions.Add(actionViewPhoneRings); var transIncomingCall = new Transition("TransitionIncomingCall", "StatePhoneIdle", "StatePhoneRings", emptyList, IncomingCallActions, "OnLineExternalActive"); // transition CallBlocked var CallBlockedActions = new List<StateMachineAction>(); CallBlockedActions.Add(actionViewPhoneIdle); var transCallBlocked = new Transition("TransitionCallBlocked", "StatePhoneRings", "StatePhoneIdle", emptyList, CallBlockedActions, "OnReceiverDown"); // transition CallAccepted var CallAcceptedActions = new List<StateMachineAction>(); CallAcceptedActions.Add(actionViewTalking); var transCallAccepted = new Transition("TransitionCallAccepted", "StatePhoneRings", "StateTalking", emptyList, CallAcceptedActions, "OnReceiverUp"); // transition CallEnded var CallEndedActions = new List<StateMachineAction>(); CallEndedActions.Add(actionViewPhoneIdle); var transCallEnded = new Transition("TransitionCallEnded", "StateTalking", "StatePhoneIdle", emptyList, CallEndedActions, "OnReceiverDown"); // transition ErrorPhoneRings - self-transition on PhoneRings state var errorPhoneRingsActions = new List<StateMachineAction>(); errorPhoneRingsActions.Add(actionViewErrorPhoneRings); var transErrorPhoneRings = new Transition("TransitionErrorPhoneRings", "StatePhoneRings", "StatePhoneRings", emptyList, errorPhoneRingsActions, "OnBellBroken"); #endregion #region Assemble all states // create states // state: PhoneIdle var transitionsPhoneIdle = new Dictionary<string, Transition>(); var entryActionsPhoneIdle = new List<StateMachineAction>(); var exitActionsPhoneIdle = new List<StateMachineAction>(); transitionsPhoneIdle.Add("TransitionIncomingCall", transIncomingCall); // Always specify all action lists, even empty ones, do not pass null into a state Lists are read via foreach, which will return an error var phoneIdle = new State("StatePhoneIdle", transitionsPhoneIdle, entryActionsPhoneIdle, exitActionsPhoneIdle, true); // state: PhoneRings var transitionsPhoneRings = new Dictionary<string, Transition>(); var entryActionsPhoneRings = new List<StateMachineAction>(); entryActionsPhoneRings.Add(actionBellRings); var exitActionsPhoneRings = new List<StateMachineAction>(); exitActionsPhoneRings.Add(actionBellSilent); transitionsPhoneRings.Add("TransitionCallBlocked", transCallBlocked); transitionsPhoneRings.Add("TransitionCallAccepted", transCallAccepted); transitionsPhoneRings.Add("TransitionErrorPhoneRings", transErrorPhoneRings); // Always specify all action lists, even empty ones, do not pass null into a state Lists are read via foreach, which will return an error var phoneRings = new State("StatePhoneRings", transitionsPhoneRings, entryActionsPhoneRings, exitActionsPhoneRings); // state: Talking var transitionsTalking = new Dictionary<string, Transition>(); var entryActionsTalking = new List<StateMachineAction>(); entryActionsTalking.Add(actionLineActive); var exitActionsTalking = new List<StateMachineAction>(); exitActionsTalking.Add(actionLineOff); transitionsTalking.Add("TransitionCallEnded", transCallEnded); // Always specify all action lists, even empty ones, do not pass null into a state Lists are read via foreach, which will return an error var talking = new State("StateTalking", transitionsTalking, entryActionsTalking, exitActionsTalking); this.TelephoneStateMachineStateList = new Dictionary<string, State> { {"StatePhoneIdle", phoneIdle}, {"StatePhoneRings", phoneRings}, {"StateTalking", talking} }; #endregion // Application Services #region Appilcation Services // Get application services this.TelephoneEventManager = EventManager.Instance; this.TelephoneViewManager = ViewManager.Instance; this.TelephoneLogManager = LogManager.Instance; this.TelephoneDeviceManager = DeviceManager.Instance; #endregion }