File: StateMachineSubscription.cs
Project: ndp\cdf\src\WF\Activities\System.Workflow.Activities.csproj (System.Workflow.Activities)
#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
{
    #region StateMachineSubscription
 
    [Serializable]
    internal abstract class StateMachineSubscription : IActivityEventListener<QueueEventArgs>
    {
        #region Member Variables
 
        private Guid _subscriptionId;
 
        #endregion Member Variables
 
        #region Properties
 
        internal Guid SubscriptionId
        {
            get
            {
                return _subscriptionId;
            }
            set
            {
                _subscriptionId = value;
            }
        }
 
        #endregion Properties
 
        void IActivityEventListener<QueueEventArgs>.OnEvent(object sender, QueueEventArgs e)
        {
            ActivityExecutionContext context = sender as ActivityExecutionContext;
            if (context == null)
                throw new ArgumentException(SR.Error_SenderMustBeActivityExecutionContext, "sender");
 
            Enqueue(context);
        }
 
        protected abstract void Enqueue(ActivityExecutionContext context);
        internal abstract void ProcessEvent(ActivityExecutionContext context);
    }
 
    #endregion StateMachineSubscription
 
    #region EventActivitySubscription
 
    [Serializable]
    internal class EventActivitySubscription : StateMachineSubscription
    {
        #region Member Variables
 
        private string _eventActivityName = String.Empty;
        private string _eventDrivenName = String.Empty;
        private string _stateName = String.Empty;
        private IComparable _queueName;
 
        #endregion Member Variables
 
        #region Properties
 
        internal string EventActivityName
        {
            get
            {
                return _eventActivityName;
            }
        }
 
        internal string StateName
        {
            get
            {
                return _stateName;
            }
        }
 
        internal IComparable QueueName
        {
            get
            {
                return _queueName;
            }
        }
 
        internal string EventDrivenName
        {
            get
            {
                return _eventDrivenName;
            }
        }
 
        #endregion Properties
 
        internal void Subscribe(ActivityExecutionContext context,
            StateActivity state,
            IEventActivity eventActivity)
        {
            eventActivity.Subscribe(context, this);
            Activity activity = (Activity)eventActivity;
            this._queueName = eventActivity.QueueName;
            this._eventActivityName = activity.QualifiedName;
            this._stateName = state.QualifiedName;
            this.SubscriptionId = Guid.NewGuid();
            EventDrivenActivity eventDriven = StateMachineHelpers.GetParentEventDriven(eventActivity);
            this._eventDrivenName = eventDriven.QualifiedName;
        }
 
        internal void Unsubscribe(ActivityExecutionContext context,
            IEventActivity eventActivity)
        {
            eventActivity.Unsubscribe(context, this);
        }
 
        protected override void Enqueue(ActivityExecutionContext context)
        {
            StateActivity rootState = StateMachineHelpers.GetRootState((StateActivity)context.Activity);
            StateMachineExecutionState executionState = StateMachineExecutionState.Get(rootState);
            executionState.SubscriptionManager.Enqueue(context, this.QueueName);
        }
 
        internal override void ProcessEvent(ActivityExecutionContext context)
        {
            StateActivity rootState = StateMachineHelpers.GetRootState((StateActivity)context.Activity);
            StateMachineExecutionState executionState = StateMachineExecutionState.Get(rootState);
            ExternalEventAction action = new ExternalEventAction(this.StateName, this.EventDrivenName);
            Debug.Assert(!executionState.HasEnqueuedActions);
            executionState.EnqueueAction(action);
            executionState.ProcessActions(context);
        }
    }
 
    #endregion EventActivitySubscription
 
    #region SetStateSubscription
 
    [Serializable]
    internal class SetStateSubscription : StateMachineSubscription
    {
        private Guid _instanceId;
 
        internal SetStateSubscription(Guid instanceId)
        {
            this._instanceId = instanceId;
        }
 
        internal void CreateQueue(ActivityExecutionContext context)
        {
            if (!StateMachineHelpers.IsRootExecutionContext(context))
            {
                // we only subscribe to the set state event if
                // we're at the root level. If this instance is
                // being called, it is not possible to set the
                // state from the host side directly
                return;
            }
 
            WorkflowQueuingService workflowQueuingService = context.GetService<WorkflowQueuingService>();
 
            MessageEventSubscription subscription = new MessageEventSubscription(
                StateMachineWorkflowActivity.SetStateQueueName,
                this._instanceId);
 
            WorkflowQueue workflowQueue = workflowQueuingService.CreateWorkflowQueue(
                StateMachineWorkflowActivity.SetStateQueueName,
                true);
            this.SubscriptionId = subscription.SubscriptionId;
        }
 
        internal void DeleteQueue(ActivityExecutionContext context)
        {
            if (!StateMachineHelpers.IsRootExecutionContext(context))
            {
                // we only subscribe to the set state event if
                // we're at the root level. If this instance is
                // being called, it is not possible to set the
                // state from the host side directly
                return;
            }
 
            WorkflowQueuingService workflowQueuingService = context.GetService<WorkflowQueuingService>();
            WorkflowQueue workflowQueue = workflowQueuingService.GetWorkflowQueue(StateMachineWorkflowActivity.SetStateQueueName);
            workflowQueuingService.DeleteWorkflowQueue(StateMachineWorkflowActivity.SetStateQueueName);
        }
 
        internal void Subscribe(ActivityExecutionContext context)
        {
            WorkflowQueuingService workflowQueuingService = context.GetService<WorkflowQueuingService>();
            WorkflowQueue workflowQueue = workflowQueuingService.GetWorkflowQueue(StateMachineWorkflowActivity.SetStateQueueName);
            workflowQueue.RegisterForQueueItemAvailable(this);
        }
 
        internal void Unsubscribe(ActivityExecutionContext context)
        {
            WorkflowQueuingService workflowQueuingService = context.GetService<WorkflowQueuingService>();
            WorkflowQueue workflowQueue = workflowQueuingService.GetWorkflowQueue(StateMachineWorkflowActivity.SetStateQueueName);
            workflowQueue.UnregisterForQueueItemAvailable(this);
        }
 
        protected override void Enqueue(ActivityExecutionContext context)
        {
            StateActivity rootState = StateMachineHelpers.GetRootState((StateActivity)context.Activity);
            StateMachineExecutionState executionState = StateMachineExecutionState.Get(rootState);
            executionState.SubscriptionManager.Enqueue(context, this.SubscriptionId);
        }
 
        internal override void ProcessEvent(ActivityExecutionContext context)
        {
            WorkflowQueuingService workflowQueuingService = context.GetService<WorkflowQueuingService>();
            WorkflowQueue workflowQueue = workflowQueuingService.GetWorkflowQueue(StateMachineWorkflowActivity.SetStateQueueName);
            SetStateEventArgs eventArgs = workflowQueue.Dequeue() as SetStateEventArgs;
            StateActivity currentState = StateMachineHelpers.GetCurrentState(context);
            if (currentState == null)
                throw new InvalidOperationException(SR.GetStateMachineWorkflowMustHaveACurrentState());
 
            StateActivity rootState = StateMachineHelpers.GetRootState((StateActivity)context.Activity);
            StateMachineExecutionState executionState = StateMachineExecutionState.Get(rootState);
            SetStateAction action = new SetStateAction(currentState.QualifiedName, eventArgs.TargetStateName);
            Debug.Assert(!executionState.HasEnqueuedActions);
            executionState.EnqueueAction(action);
            executionState.ProcessActions(context);
        }
    }
 
    #endregion SetStateSubscription
}