/// <summary> /// Goes recursively up the state hierarchy until a state is found that can handle the event. /// </summary> /// <param name="stateDefinition">The state definition of the state in which the event should be fired.</param> /// <param name="context">The event context.</param> /// <param name="lastActiveStateModifier">The last active state modifier.</param> /// <param name="stateDefinitions">The definitions for all states of this state Machine.</param> /// <returns>The result of the transition.</returns> public async Task <ITransitionResult <TState> > Fire( IStateDefinition <TState, TEvent> stateDefinition, ITransitionContext <TState, TEvent> context, ILastActiveStateModifier <TState> lastActiveStateModifier, IStateDefinitionDictionary <TState, TEvent> stateDefinitions) { Guard.AgainstNullArgument("context", context); var result = TransitionResult <TState> .NotFired; if (stateDefinition.Transitions.TryGetValue(context.EventId.Value, out var transitionsForEvent)) { foreach (var transitionDefinition in transitionsForEvent) { result = await this.transitionLogic.Fire(transitionDefinition, context, lastActiveStateModifier, stateDefinitions) .ConfigureAwait(false); if (result.Fired) { return(result); } } } if (stateDefinition.SuperState != null) { result = await this.Fire(stateDefinition.SuperState, context, lastActiveStateModifier, stateDefinitions) .ConfigureAwait(false); } return(result); }
/// <summary> /// Fires the specified event. /// </summary> /// <param name="eventId">The event.</param> /// <param name="eventArgument">The event argument.</param> /// <param name="stateContainer">Contains all mutable state of of the state machine.</param> /// <param name="stateMachineInformation">The state machine information.</param> /// <param name="stateDefinitions">The definitions for all states of this state Machine.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task Fire( TEvent eventId, object eventArgument, StateContainer <TState, TEvent> stateContainer, IStateMachineInformation <TState, TEvent> stateMachineInformation, IStateDefinitionDictionary <TState, TEvent> stateDefinitions) { CheckThatStateMachineHasEnteredInitialState(stateContainer); await stateContainer.ForEach(extension => extension.FiringEvent(stateMachineInformation, ref eventId, ref eventArgument)) .ConfigureAwait(false); var currentState = stateContainer.CurrentState.ExtractOrThrow(); var context = this.factory.CreateTransitionContext(currentState, new Missable <TEvent>(eventId), eventArgument, this); var result = await this.stateLogic.Fire(currentState, context, stateContainer) .ConfigureAwait(false); if (!result.Fired) { this.OnTransitionDeclined(context); return; } var newState = stateDefinitions[result.NewState]; await SwitchStateTo(newState, stateContainer, stateMachineInformation) .ConfigureAwait(false); await stateContainer.ForEach(extension => extension.FiredEvent(stateMachineInformation, context)) .ConfigureAwait(false); this.OnTransitionCompleted(context, stateMachineInformation); }
/// <summary> /// Fires the specified event. /// </summary> /// <param name="eventId">The event.</param> /// <param name="stateContainer">Contains all mutable state of of the state machine.</param> /// <param name="stateDefinitions">The definitions for all states of this state Machine.</param> public void Fire( TEvent eventId, StateContainer <TState, TEvent> stateContainer, IStateDefinitionDictionary <TState, TEvent> stateDefinitions) { this.Fire(eventId, Missing.Value, stateContainer, stateDefinitions); }
/// <summary> /// Fires the specified event. /// </summary> /// <param name="eventId">The event.</param> /// <param name="eventArgument">The event argument.</param> /// <param name="stateContainer">Contains all mutable state of of the state machine.</param> /// <param name="stateDefinitions">The definitions for all states of this state Machine.</param> public void Fire( TEvent eventId, object eventArgument, StateContainer <TState, TEvent> stateContainer, IStateDefinitionDictionary <TState, TEvent> stateDefinitions) { CheckThatStateMachineHasEnteredInitialState(stateContainer); stateContainer.ForEach(extension => extension.FiringEvent(ref eventId, ref eventArgument)); var currentState = stateContainer .CurrentStateId .Map(x => stateDefinitions[x]) .ExtractOrThrow(); var context = this.factory.CreateTransitionContext(currentState, new Missable <TEvent>(eventId), eventArgument, this); var result = this.stateLogic.Fire(currentState, context, stateContainer, stateDefinitions); if (!result.Fired) { this.OnTransitionDeclined(context); return; } var newState = stateDefinitions[result.NewState]; SwitchStateTo(newState, stateContainer, stateDefinitions); stateContainer.ForEach(extension => extension.FiredEvent(context)); this.OnTransitionCompleted(context, stateContainer.CurrentStateId.ExtractOrThrow()); }
public async Task <TState> EnterByHistory( IStateDefinition <TState, TEvent> stateDefinition, ITransitionContext <TState, TEvent> context, ILastActiveStateModifier <TState> lastActiveStateModifier, IStateDefinitionDictionary <TState, TEvent> stateDefinitions) { var result = stateDefinition.Id; switch (stateDefinition.HistoryType) { case HistoryType.None: result = await this.EnterHistoryNone(stateDefinition, context) .ConfigureAwait(false); break; case HistoryType.Shallow: result = await this.EnterHistoryShallow(stateDefinition, context, lastActiveStateModifier, stateDefinitions) .ConfigureAwait(false); break; case HistoryType.Deep: result = await this.EnterHistoryDeep(stateDefinition, context, lastActiveStateModifier, stateDefinitions) .ConfigureAwait(false); break; } return(result); }
public StateMachineDefinition( IStateDefinitionDictionary <TState, TEvent> stateDefinitions, IReadOnlyDictionary <TState, IStateDefinition <TState, TEvent> > initiallyLastActiveStates, TState initialState) { this.stateDefinitions = stateDefinitions; this.initiallyLastActiveStates = initiallyLastActiveStates; this.initialState = initialState; }
public async Task <ITransitionResult <TState> > Fire( ITransitionDefinition <TState, TEvent> transitionDefinition, ITransitionContext <TState, TEvent> context, ILastActiveStateModifier <TState> lastActiveStateModifier, IStateDefinitionDictionary <TState, TEvent> stateDefinitions) { Guard.AgainstNullArgument("context", context); var shouldFire = await this.ShouldFire(transitionDefinition, context).ConfigureAwait(false); if (!shouldFire) { await this.extensionHost .ForEach(extension => extension.SkippedTransition( transitionDefinition, context)) .ConfigureAwait(false); return(TransitionResult <TState> .NotFired); } context.OnTransitionBegin(); await this.extensionHost .ForEach(extension => extension.ExecutingTransition( transitionDefinition, context)) .ConfigureAwait(false); var newState = context.StateDefinition.Id; if (!transitionDefinition.IsInternalTransition) { await this.UnwindSubStates(transitionDefinition, context, lastActiveStateModifier).ConfigureAwait(false); await this.Fire(transitionDefinition, transitionDefinition.Source, transitionDefinition.Target, context, lastActiveStateModifier) .ConfigureAwait(false); newState = await this.stateLogic.EnterByHistory(transitionDefinition.Target, context, lastActiveStateModifier, stateDefinitions) .ConfigureAwait(false); } else { await this.PerformActions(transitionDefinition, context).ConfigureAwait(false); } await this.extensionHost .ForEach(extension => extension.ExecutedTransition( transitionDefinition, context)) .ConfigureAwait(false); return(new TransitionResult <TState>(true, newState)); }
public ActiveStateMachine( StateMachine <TState, TEvent> stateMachine, StateContainer <TState, TEvent> stateContainer, IStateDefinitionDictionary <TState, TEvent> stateDefinitions, TState initialState) { this.stateMachine = stateMachine; this.stateContainer = stateContainer; this.stateDefinitions = stateDefinitions; this.initialState = initialState; }
public TState EnterInitialState( IStateLogic <TState, TEvent> stateLogic, ILastActiveStateModifier <TState> lastActiveStateModifier, IStateDefinitionDictionary <TState, TEvent> stateDefinitions) { var stack = this.TraverseUpTheStateHierarchy(); this.TraverseDownTheStateHierarchyAndEnterStates(stateLogic, stack); return(stateLogic.EnterByHistory(this.initialState, this.context, lastActiveStateModifier, stateDefinitions)); }
public PassiveStateMachine( StateMachine <TState, TEvent> stateMachine, StateContainer <TState, TEvent> stateContainer, IStateDefinitionDictionary <TState, TEvent> stateDefinitions, TState initialState) { this.stateMachine = stateMachine; this.stateContainer = stateContainer; this.stateDefinitions = stateDefinitions; this.initialState = initialState; this.events = new LinkedList <EventInformation <TEvent> >(); }
public async Task <TState> EnterInitialState( IStateLogic <TState, TEvent> stateLogic, ILastActiveStateModifier <TState> lastActiveStateModifier, IStateDefinitionDictionary <TState, TEvent> stateDefinitions) { var stack = this.TraverseUpTheStateHierarchy(); await this.TraverseDownTheStateHierarchyAndEnterStates(stateLogic, stack) .ConfigureAwait(false); return(await stateLogic.EnterByHistory(this.initialState, this.context, lastActiveStateModifier, stateDefinitions) .ConfigureAwait(false)); }
/// <summary> /// Enters the initial state as specified with <paramref name="initialState"/>. /// </summary> /// <param name="stateContainer">Contains all mutable state of of the state machine.</param> /// <param name="stateDefinitions">The definitions for all states of this state Machine.</param> /// <param name="initialState">The initial state the state machine should enter.</param> public void EnterInitialState( StateContainer <TState, TEvent> stateContainer, IStateDefinitionDictionary <TState, TEvent> stateDefinitions, TState initialState) { stateContainer.ForEach(extension => extension.EnteringInitialState(initialState)); var context = this.factory.CreateTransitionContext(null, new Missable <TEvent>(), Missing.Value, this); this.EnterInitialState(context, stateContainer, stateDefinitions, initialState); stateContainer.ForEach(extension => extension.EnteredInitialState(initialState, context)); }
private void EnterInitialState( ITransitionContext <TState, TEvent> context, StateContainer <TState, TEvent> stateContainer, IStateDefinitionDictionary <TState, TEvent> stateDefinitions, TState initialStateId) { var initialState = stateDefinitions[initialStateId]; var initializer = this.factory.CreateStateMachineInitializer(initialState, context); var newStateId = initializer.EnterInitialState(this.stateLogic, stateContainer, stateDefinitions); var newStateDefinition = stateDefinitions[newStateId]; SwitchStateTo(newStateDefinition, stateContainer, stateDefinitions); }
public AsyncPassiveStateMachine( StateMachine <TState, TEvent> stateMachine, StateContainer <TState, TEvent> stateContainer, IStateDefinitionDictionary <TState, TEvent> stateDefinitions, TState initialState) { this.stateMachine = stateMachine; this.stateContainer = stateContainer; this.stateDefinitions = stateDefinitions; this.initialState = initialState; this.events = new ConcurrentQueue <EventInformation <TEvent> >(); this.priorityEvents = new ConcurrentStack <EventInformation <TEvent> >(); }
private static void SwitchStateTo( IStateDefinition <TState, TEvent> newState, StateContainer <TState, TEvent> stateContainer, IStateDefinitionDictionary <TState, TEvent> stateDefinitions) { var oldState = stateContainer .CurrentStateId .Map(x => stateDefinitions[x]) .ExtractOr(null); stateContainer.CurrentStateId = Initializable <TState> .Initialized(newState.Id); stateContainer.ForEach(extension => extension.SwitchedState(oldState, newState)); }
/// <summary> /// Enters the initial state as specified with <paramref name="initialState"/>. /// </summary> /// <param name="stateContainer">Contains all mutable state of of the state machine.</param> /// <param name="stateDefinitions">The definitions for all states of this state Machine.</param> /// <param name="initialState">The initial state the state machine should enter.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task EnterInitialState( StateContainer <TState, TEvent> stateContainer, IStateDefinitionDictionary <TState, TEvent> stateDefinitions, TState initialState) { await stateContainer.ForEach(extension => extension.EnteringInitialState(initialState)) .ConfigureAwait(false); var context = this.factory.CreateTransitionContext(null, new Missable <TEvent>(), Missing.Value, this); await this.EnterInitialState(context, stateContainer, stateDefinitions, initialState) .ConfigureAwait(false); await stateContainer.ForEach(extension => extension.EnteredInitialState(initialState, context)) .ConfigureAwait(false); }
private async Task EnterInitialState( ITransitionContext <TState, TEvent> context, StateContainer <TState, TEvent> stateContainer, IStateDefinitionDictionary <TState, TEvent> stateDefinitions, TState initialStateId) { var initialState = stateDefinitions[initialStateId]; var initializer = this.factory.CreateStateMachineInitializer(initialState, context); var newStateId = await initializer.EnterInitialState(this.stateLogic, stateContainer, stateDefinitions). ConfigureAwait(false); var newStateDefinition = stateDefinitions[newStateId]; await SwitchStateTo(newStateDefinition, stateContainer, stateDefinitions) .ConfigureAwait(false); }
private TState EnterHistoryShallow( IStateDefinition <TState, TEvent> stateDefinition, ITransitionContext <TState, TEvent> context, ILastActiveStateModifier <TState> lastActiveStateModifier, IStateDefinitionDictionary <TState, TEvent> stateDefinitions) { var lastActiveStateId = lastActiveStateModifier.GetLastActiveStateFor(stateDefinition.Id); if (!lastActiveStateId.HasValue) { return(stateDefinition.Id); } var lastActiveState = stateDefinitions[lastActiveStateId.Value]; return(this.EnterShallow(lastActiveState, context)); }
private async Task <TState> EnterHistoryDeep( IStateDefinition <TState, TEvent> stateDefinition, ITransitionContext <TState, TEvent> context, ILastActiveStateModifier <TState> lastActiveStateModifier, IStateDefinitionDictionary <TState, TEvent> stateDefinitions) { var lastActiveStateId = lastActiveStateModifier.GetLastActiveStateFor(stateDefinition.Id); if (!lastActiveStateId.HasValue) { return(stateDefinition.Id); } var lastActiveState = stateDefinitions[lastActiveStateId.Value]; return(await this.EnterDeep(lastActiveState, context, lastActiveStateModifier, stateDefinitions) .ConfigureAwait(false)); }
/// <summary> /// Initializes a new instance of the <see cref="StateMachineTest"/> class. /// </summary> public StateMachineTest() { var stateDefinitionBuilder = new StateDefinitionsBuilder <States, Events>(); stateDefinitionBuilder .DefineHierarchyOn(States.B) .WithHistoryType(HistoryType.None) .WithInitialSubState(States.B1) .WithSubState(States.B2); stateDefinitionBuilder .DefineHierarchyOn(States.C) .WithHistoryType(HistoryType.Shallow) .WithInitialSubState(States.C2) .WithSubState(States.C1); stateDefinitionBuilder .DefineHierarchyOn(States.C1) .WithHistoryType(HistoryType.Shallow) .WithInitialSubState(States.C1A) .WithSubState(States.C1B); stateDefinitionBuilder .DefineHierarchyOn(States.D) .WithHistoryType(HistoryType.Deep) .WithInitialSubState(States.D1) .WithSubState(States.D2); stateDefinitionBuilder .DefineHierarchyOn(States.D1) .WithHistoryType(HistoryType.Deep) .WithInitialSubState(States.D1A) .WithSubState(States.D1B); stateDefinitionBuilder .In(States.A) .ExecuteOnEntry(() => this.RecordEntry(States.A)) .ExecuteOnExit(() => this.RecordExit(States.A)) .On(Events.B).Goto(States.B) .On(Events.C).Goto(States.C) .On(Events.D).Goto(States.D) .On(Events.A); stateDefinitionBuilder .In(States.B) .ExecuteOnEntry(() => this.RecordEntry(States.B)) .ExecuteOnExit(() => this.RecordExit(States.B)) .On(Events.D).Goto(States.D); stateDefinitionBuilder .In(States.B1) .ExecuteOnEntry(() => this.RecordEntry(States.B1)) .ExecuteOnExit(() => this.RecordExit(States.B1)) .On(Events.B2).Goto(States.B2); stateDefinitionBuilder .In(States.B2) .ExecuteOnEntry(() => this.RecordEntry(States.B2)) .ExecuteOnExit(() => this.RecordExit(States.B2)) .On(Events.A).Goto(States.A) .On(Events.C1B).Goto(States.C1B); stateDefinitionBuilder .In(States.C) .ExecuteOnEntry(() => this.RecordEntry(States.C)) .ExecuteOnExit(() => this.RecordExit(States.C)) .On(Events.A).Goto(States.A); stateDefinitionBuilder .In(States.C1) .ExecuteOnEntry(() => this.RecordEntry(States.C1)) .ExecuteOnExit(() => this.RecordExit(States.C1)) .On(Events.C1B).Goto(States.C1B); stateDefinitionBuilder .In(States.C2) .ExecuteOnEntry(() => this.RecordEntry(States.C2)) .ExecuteOnExit(() => this.RecordExit(States.C2)); stateDefinitionBuilder .In(States.C1A) .ExecuteOnEntry(() => this.RecordEntry(States.C1A)) .ExecuteOnExit(() => this.RecordExit(States.C1A)); stateDefinitionBuilder .In(States.C1B) .ExecuteOnEntry(() => this.RecordEntry(States.C1B)) .ExecuteOnExit(() => this.RecordExit(States.C1B)); stateDefinitionBuilder .In(States.D) .ExecuteOnEntry(() => this.RecordEntry(States.D)) .ExecuteOnExit(() => this.RecordExit(States.D)); stateDefinitionBuilder .In(States.D1) .ExecuteOnEntry(() => this.RecordEntry(States.D1)) .ExecuteOnExit(() => this.RecordExit(States.D1)); stateDefinitionBuilder .In(States.D1A) .ExecuteOnEntry(() => this.RecordEntry(States.D1A)) .ExecuteOnExit(() => this.RecordExit(States.D1A)); stateDefinitionBuilder .In(States.D1B) .ExecuteOnEntry(() => this.RecordEntry(States.D1B)) .ExecuteOnExit(() => this.RecordExit(States.D1B)) .On(Events.A).Goto(States.A) .On(Events.B1).Goto(States.B1); stateDefinitionBuilder .In(States.D2) .ExecuteOnEntry(() => this.RecordEntry(States.D2)) .ExecuteOnExit(() => this.RecordExit(States.D2)) .On(Events.A).Goto(States.A); stateDefinitionBuilder .In(States.E) .ExecuteOnEntry(() => this.RecordEntry(States.E)) .ExecuteOnExit(() => this.RecordExit(States.E)) .On(Events.A).Goto(States.A) .On(Events.E).Goto(States.E); this.stateDefinitions = stateDefinitionBuilder.Build(); }