Ejemplo n.º 1
0
        /// <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);
        }
Ejemplo n.º 2
0
        /// <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);
        }
Ejemplo n.º 3
0
 /// <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);
 }
Ejemplo n.º 4
0
        /// <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());
        }
Ejemplo n.º 5
0
        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);
        }
Ejemplo n.º 6
0
 public StateMachineDefinition(
     IStateDefinitionDictionary <TState, TEvent> stateDefinitions,
     IReadOnlyDictionary <TState, IStateDefinition <TState, TEvent> > initiallyLastActiveStates,
     TState initialState)
 {
     this.stateDefinitions          = stateDefinitions;
     this.initiallyLastActiveStates = initiallyLastActiveStates;
     this.initialState = initialState;
 }
Ejemplo n.º 7
0
        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));
        }
Ejemplo n.º 8
0
 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));
        }
Ejemplo n.º 10
0
 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));
        }
Ejemplo n.º 12
0
        /// <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));
        }
Ejemplo n.º 13
0
        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> >();
 }
Ejemplo n.º 15
0
        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));
        }
Ejemplo n.º 16
0
        /// <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);
        }
Ejemplo n.º 17
0
        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);
        }
Ejemplo n.º 18
0
        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));
        }
Ejemplo n.º 19
0
        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));
        }
Ejemplo n.º 20
0
        /// <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();
        }