e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
269 lines
8.0 KiB
C#
269 lines
8.0 KiB
C#
#region Using directives
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Specialized;
|
|
using System.Reflection;
|
|
using System.Diagnostics;
|
|
using System.Runtime.Remoting.Messaging;
|
|
using System.Workflow.ComponentModel;
|
|
using System.Workflow.ComponentModel.Design;
|
|
using System.Workflow.Runtime;
|
|
using System.Workflow.Runtime.Hosting;
|
|
|
|
#endregion Using directives
|
|
|
|
namespace System.Workflow.Activities
|
|
{
|
|
[Serializable]
|
|
internal class StateMachineExecutionState
|
|
{
|
|
#region Member Variables
|
|
|
|
internal const string StateMachineExecutionStateKey = "StateMachineExecutionState";
|
|
private StateMachineSubscriptionManager _subscriptionManager;
|
|
private Queue<StateMachineAction> _actions;
|
|
private string _currentStateName;
|
|
private string _previousStateName;
|
|
private string _nextStateName;
|
|
private bool _completed = false;
|
|
private bool _queueLocked = false;
|
|
private bool _schedulerBusy = false;
|
|
|
|
#endregion Member Variables
|
|
|
|
#region Properties
|
|
|
|
internal StateMachineSubscriptionManager SubscriptionManager
|
|
{
|
|
get
|
|
{
|
|
return _subscriptionManager;
|
|
}
|
|
}
|
|
|
|
private Queue<StateMachineAction> Actions
|
|
{
|
|
get
|
|
{
|
|
if (_actions == null)
|
|
_actions = new Queue<StateMachineAction>();
|
|
return _actions;
|
|
}
|
|
}
|
|
|
|
internal bool SchedulerBusy
|
|
{
|
|
get
|
|
{
|
|
return _schedulerBusy;
|
|
}
|
|
set
|
|
{
|
|
_schedulerBusy = value;
|
|
}
|
|
}
|
|
|
|
internal string CurrentStateName
|
|
{
|
|
get
|
|
{
|
|
return _currentStateName;
|
|
}
|
|
set
|
|
{
|
|
_currentStateName = value;
|
|
}
|
|
}
|
|
|
|
internal string PreviousStateName
|
|
{
|
|
get
|
|
{
|
|
return _previousStateName;
|
|
}
|
|
set
|
|
{
|
|
_previousStateName = value;
|
|
}
|
|
}
|
|
|
|
internal string NextStateName
|
|
{
|
|
get
|
|
{
|
|
return _nextStateName;
|
|
}
|
|
set
|
|
{
|
|
_nextStateName = value;
|
|
}
|
|
}
|
|
|
|
internal bool Completed
|
|
{
|
|
get
|
|
{
|
|
return _completed;
|
|
}
|
|
set
|
|
{
|
|
_completed = value;
|
|
}
|
|
}
|
|
|
|
internal bool HasEnqueuedActions
|
|
{
|
|
get
|
|
{
|
|
return this.Actions.Count > 0;
|
|
}
|
|
}
|
|
|
|
#endregion Properties
|
|
|
|
#region Constructors
|
|
|
|
internal StateMachineExecutionState(Guid instanceId)
|
|
{
|
|
_subscriptionManager = new StateMachineSubscriptionManager(this, instanceId);
|
|
}
|
|
|
|
#endregion
|
|
|
|
internal void LockQueue()
|
|
{
|
|
_queueLocked = true;
|
|
}
|
|
|
|
internal void EnqueueAction(StateMachineAction action)
|
|
{
|
|
Debug.Assert(!this._queueLocked);
|
|
this.Actions.Enqueue(action);
|
|
}
|
|
|
|
internal StateMachineAction DequeueAction()
|
|
{
|
|
StateMachineAction action = this.Actions.Dequeue();
|
|
if (this.Actions.Count == 0)
|
|
_queueLocked = false;
|
|
return action;
|
|
}
|
|
|
|
internal void ProcessActions(ActivityExecutionContext context)
|
|
{
|
|
if (context == null)
|
|
throw new ArgumentNullException("context");
|
|
|
|
if (this.SchedulerBusy)
|
|
return;
|
|
|
|
StateActivity state = (StateActivity)context.Activity;
|
|
|
|
if (this.Actions.Count == 0)
|
|
{
|
|
this.SubscriptionManager.ProcessQueue(context);
|
|
return;
|
|
}
|
|
|
|
StateMachineAction action = this.Actions.Peek();
|
|
while (action.StateName.Equals(state.QualifiedName))
|
|
{
|
|
action = DequeueAction();
|
|
action.Execute(context);
|
|
|
|
// If the previous action just
|
|
// requested something to the runtime
|
|
// scheduler, then we quit, since
|
|
// the scheduler takes precedence.
|
|
// we'll pick up the processing of actions
|
|
// after the scheduler return the control to us.
|
|
if (this.SchedulerBusy)
|
|
return;
|
|
|
|
if (this.Actions.Count == 0)
|
|
break;
|
|
|
|
action = this.Actions.Peek();
|
|
}
|
|
|
|
if (this.Actions.Count > 0)
|
|
{
|
|
StateActivity rootState = StateMachineHelpers.GetRootState(state);
|
|
StateActivity nextActionState = StateMachineHelpers.FindDynamicStateByName(rootState, action.StateName);
|
|
if (nextActionState == null)
|
|
throw new InvalidOperationException(SR.GetInvalidStateMachineAction(action.StateName));
|
|
|
|
nextActionState.RaiseProcessActionEvent(context);
|
|
}
|
|
else
|
|
{
|
|
this.SubscriptionManager.ProcessQueue(context);
|
|
}
|
|
}
|
|
|
|
|
|
internal void ProcessTransitionRequest(ActivityExecutionContext context)
|
|
{
|
|
if (String.IsNullOrEmpty(this.NextStateName))
|
|
return;
|
|
|
|
StateActivity currentState = StateMachineHelpers.GetCurrentState(context);
|
|
CalculateStateTransition(currentState, this.NextStateName);
|
|
LockQueue();
|
|
this.NextStateName = null;
|
|
}
|
|
|
|
internal void CalculateStateTransition(StateActivity currentState, string targetStateName)
|
|
{
|
|
if (currentState == null)
|
|
throw new ArgumentNullException("currentState");
|
|
if (String.IsNullOrEmpty(targetStateName))
|
|
throw new ArgumentNullException("targetStateName");
|
|
|
|
while (currentState != null && (currentState.QualifiedName.Equals(targetStateName) || !StateMachineHelpers.ContainsState(currentState, targetStateName)))
|
|
{
|
|
CloseStateAction action = new CloseStateAction(currentState.QualifiedName);
|
|
this.Actions.Enqueue(action);
|
|
currentState = currentState.Parent as StateActivity;
|
|
}
|
|
if (currentState == null)
|
|
throw new InvalidOperationException(SR.GetUnableToTransitionToState(targetStateName));
|
|
|
|
while (!currentState.QualifiedName.Equals(targetStateName))
|
|
{
|
|
foreach (Activity childActivity in currentState.EnabledActivities)
|
|
{
|
|
StateActivity childState = childActivity as StateActivity;
|
|
if (childState != null)
|
|
{
|
|
//
|
|
if (StateMachineHelpers.ContainsState(childState, targetStateName))
|
|
{
|
|
ExecuteChildStateAction action = new ExecuteChildStateAction(currentState.QualifiedName, childState.QualifiedName);
|
|
this.Actions.Enqueue(action);
|
|
currentState = childState;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!StateMachineHelpers.IsLeafState(currentState))
|
|
throw new InvalidOperationException(SR.GetInvalidStateTransitionPath());
|
|
}
|
|
|
|
#region Static Methods
|
|
|
|
internal static StateMachineExecutionState Get(StateActivity state)
|
|
{
|
|
Debug.Assert(StateMachineHelpers.IsRootState(state));
|
|
StateMachineExecutionState executionState = (StateMachineExecutionState)state.GetValue(StateActivity.StateMachineExecutionStateProperty);
|
|
Debug.Assert(executionState != null);
|
|
return executionState;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|