ConstrainedGroup.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WF / Activities / ConstrainedGroup.cs / 1305376 / ConstrainedGroup.cs

                            namespace System.Workflow.Activities 
{
    #region Imports

    using System; 
    using System.Diagnostics;
    using System.Xml; 
    using System.CodeDom; 
    using System.Drawing;
    using System.Collections; 
    using System.Windows.Forms;
    using System.ComponentModel;
    using System.Drawing.Drawing2D;
    using System.Collections.Generic; 
    using System.Windows.Forms.Design;
    using System.ComponentModel.Design; 
    using System.Workflow.ComponentModel; 
    using System.Workflow.ComponentModel.Design;
    using System.ComponentModel.Design.Serialization; 
    using System.Workflow.ComponentModel.Compiler;
    using System.Workflow.Runtime.DebugEngine;
    using System.Workflow.Activities.Common;
 
    #endregion
 
    [SRDescription(SR.ConstrainedGroupActivityDescription)] 
    [ToolboxItem(typeof(ActivityToolboxItem))]
    [Designer(typeof(ConditionedActivityGroupDesigner), typeof(IDesigner))] 
    [ToolboxBitmap(typeof(ConditionedActivityGroup), "Resources.cag.png")]
    [ActivityValidator(typeof(ConditionedActivityGroupValidator))]
    [SRCategory(SR.Standard)]
    [WorkflowDebuggerSteppingAttribute(WorkflowDebuggerSteppingOption.Concurrent)] 
    public sealed class ConditionedActivityGroup : CompositeActivity, IActivityEventListener
    { 
        //Attached properties provided to the children 
        public static readonly DependencyProperty WhenConditionProperty = DependencyProperty.RegisterAttached("WhenCondition", typeof(ActivityCondition), typeof(ConditionedActivityGroup), new PropertyMetadata(DependencyPropertyOptions.Metadata), typeof(WhenUnlessConditionDynamicPropertyValidator));
 
        // metadata properties go here
        public static readonly DependencyProperty UntilConditionProperty = DependencyProperty.Register("UntilCondition", typeof(ActivityCondition), typeof(ConditionedActivityGroup), new PropertyMetadata(DependencyPropertyOptions.Metadata));

        #region Constructors 

        public ConditionedActivityGroup() 
        { 
        }
 
        public ConditionedActivityGroup(string name)
            : base(name)
        {
        } 

        #endregion 
 
        // WhenConditionProperty Get and Set Accessors
        public static object GetWhenCondition(object dependencyObject) 
        {
            if (dependencyObject == null)
                throw new ArgumentNullException("dependencyObject");
            if(!(dependencyObject is DependencyObject)) 
                throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(DependencyObject).FullName), "dependencyObject");
 
            return (dependencyObject as DependencyObject).GetValue(WhenConditionProperty); 
        }
 
        public static void SetWhenCondition(object dependencyObject, object value)
        {
            if (dependencyObject == null)
                throw new ArgumentNullException("dependencyObject"); 
            if (!(dependencyObject is DependencyObject))
                throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(DependencyObject).FullName), "dependencyObject"); 
 
            (dependencyObject as DependencyObject).SetValue(WhenConditionProperty, value);
        } 

        [SRCategory(SR.Conditions)]
        [SRDescription(SR.UntilConditionDescr)]
        [DefaultValue(null)] 
        public ActivityCondition UntilCondition
        { 
            get 
            {
                return base.GetValue(UntilConditionProperty) as ActivityCondition; 
            }
            set
            {
                base.SetValue(UntilConditionProperty, value); 
            }
        } 
 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        private Activity GetDynamicActivity(Activity childActivity)
        {
            if (childActivity == null)
                throw new ArgumentNullException("childActivity"); 

            if (!this.EnabledActivities.Contains(childActivity)) 
                throw new ArgumentException(SR.GetString(SR.Error_CAGChildNotFound, childActivity.QualifiedName, this.QualifiedName), "childActivity"); 
            else
            { 
                Activity[] dynamicChildActivity = this.GetDynamicActivities(childActivity);

                if (dynamicChildActivity.Length != 0)
                    return dynamicChildActivity[0]; 
                else
                    return null; 
            } 
        }
 
        public Activity GetDynamicActivity(String childActivityName)
        {
            if (childActivityName == null)
                throw new ArgumentNullException("childActivityName"); 

            Activity childActivity = null; 
 
            for (int i = 0; i < this.EnabledActivities.Count; ++i)
            { 
                if (this.EnabledActivities[i].QualifiedName.Equals(childActivityName))
                {
                    childActivity = this.EnabledActivities[i];
                    break; 
                }
            } 
 
            if (childActivity != null)
                return GetDynamicActivity(childActivity); 

            throw new ArgumentException(SR.GetString(SR.Error_CAGChildNotFound, childActivityName, this.QualifiedName), "childActivityName");
        }
 
        public int GetChildActivityExecutedCount(Activity child)
        { 
            if (child == null) 
                throw new ArgumentNullException("child");
 
            ConditionedActivityGroupStateInfo conditionedInfo = this.CAGState;

            if (conditionedInfo == null)
            { 
                throw new InvalidOperationException(SR.GetString(SR.Error_CAGNotExecuting, this.QualifiedName));
            } 
 
            if (!conditionedInfo.ChildrenStats.ContainsKey(child.QualifiedName))
            { 
                throw new ArgumentException(SR.GetString(SR.Error_CAGChildNotFound, child.QualifiedName, this.QualifiedName), "child");
            }
            else
            { 
                return conditionedInfo.ChildrenStats[child.QualifiedName].ExecutedCount;
            } 
        } 

        private sealed class WhenUnlessConditionDynamicPropertyValidator : Validator 
        {
            public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
            {
                ValidationErrorCollection validationErrors = ValidationHelpers.ValidateObject(manager, obj); 

                if (validationErrors.Count == 0) 
                { 
                    Activity activity = manager.Context[typeof(Activity)] as Activity;
                    if (activity == null) 
                        throw new InvalidOperationException(SR.GetString(SR.Error_ContextStackItemMissing, typeof(Activity).Name));

                    CodeCondition codeCondition = obj as CodeCondition;
                    if (codeCondition != null && codeCondition.IsBindingSet(CodeCondition.ConditionEvent)) 
                    {
                        ActivityBind activityBind = codeCondition.GetBinding(CodeCondition.ConditionEvent) as ActivityBind; 
                        if (activityBind != null) 
                        {
                            Activity contextActivity = Helpers.ParseActivityForBind(activity, activityBind.Name); 
                            if (contextActivity != null && Helpers.IsChildActivity(activity.Parent, contextActivity))
                            {
                                string propertyName = GetFullPropertyName(manager);
                                ValidationError error = new ValidationError(SR.GetString(SR.Error_NestedConstrainedGroupConditions, propertyName), ErrorNumbers.Error_NestedConstrainedGroupConditions); 
                                error.PropertyName = propertyName;
                                validationErrors.Add(error); 
                            } 
                        }
                    } 
                }

                return validationErrors;
            } 
        }
 
        #region Runtime Internal Dependency Property 
        static DependencyProperty CAGStateProperty = DependencyProperty.Register("CAGState", typeof(ConditionedActivityGroupStateInfo), typeof(ConditionedActivityGroup));
 
        internal ConditionedActivityGroupStateInfo CAGState
        {
            get
            { 
                return (ConditionedActivityGroupStateInfo)base.GetValue(CAGStateProperty);
            } 
            set 
            {
                base.SetValue(CAGStateProperty, value); 
            }
        }
        #endregion
 
        protected override void OnClosed(IServiceProvider provider)
        { 
            base.RemoveProperty(ConditionedActivityGroup.CAGStateProperty); 
        }
 
        #region Workflow Changes Overrides
        protected override void OnActivityChangeAdd(ActivityExecutionContext executionContext, Activity addedActivity)
        {
            if (executionContext == null) 
                throw new ArgumentNullException("executionContext");
            if (addedActivity == null) 
                throw new ArgumentNullException("addedActivity"); 

            if (!addedActivity.Enabled) 
                return;

            ConditionedActivityGroup currentActivity = executionContext.Activity as ConditionedActivityGroup;
            Debug.Assert(currentActivity != null); 

            ConditionedActivityGroupStateInfo state = currentActivity.CAGState; 
            if (currentActivity.ExecutionStatus == ActivityExecutionStatus.Executing && state != null) 
            {
                Debug.Assert(currentActivity == addedActivity.Parent, "Attempting to add wrong activity to CAG"); 
                state.ChildrenStats[addedActivity.QualifiedName] = new CAGChildStats();
            }
        }
 
        protected override void OnActivityChangeRemove(ActivityExecutionContext executionContext, Activity removedActivity)
        { 
            if (executionContext == null) 
                throw new ArgumentNullException("executionContext");
            if (removedActivity == null) 
                throw new ArgumentNullException("removedActivity");

            if (!removedActivity.Enabled)
                return; 

            ConditionedActivityGroup cag = executionContext.Activity as ConditionedActivityGroup; 
            Debug.Assert(cag != null); 

            // find out the status of the cag 

            ConditionedActivityGroupStateInfo state = cag.CAGState;
            if ((cag.ExecutionStatus == ActivityExecutionStatus.Executing) && (state != null))
            { 
                state.ChildrenStats.Remove(removedActivity.QualifiedName);
            } 
        } 

        protected override void OnWorkflowChangesCompleted(ActivityExecutionContext executionContext) 
        {
            if (executionContext == null)
                throw new ArgumentNullException("executionContext");
 
            // find out the status of the cag
            ConditionedActivityGroup currentActivity = executionContext.Activity as ConditionedActivityGroup; 
 
            // if CAG is executing... fire the conditions on the net result
            if (currentActivity.ExecutionStatus == ActivityExecutionStatus.Executing) 
            {
                // but hold on, a derived cag could be applying model changes before it
                // "really" starts executing the activities. In that case it will evaluate
                // the conditions later, at the appropriate time. 
                ConditionedActivityGroupStateInfo state = currentActivity.CAGState;
                if ((state != null) && (!state.Testing)) 
                { 
                    // fire away...  fire away... said the CAG
                    if (this.EvaluateConditions(currentActivity, executionContext)) 
                    {
                        // CAG until indicates we are done, so no children execute
                        this.Cleanup(currentActivity, executionContext);
                    } 
                    else
                    { 
                        // start any pending activity required 
                        this.TriggerChildren(currentActivity, executionContext);
                    } 
                }
            }
        }
 
        #endregion
 
        #region Execution Implementation 
#if	LOG
        private static void Log(string message) 
        {
            Trace.WriteLine(message);
        }
#endif 

        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) 
        { 
            if (executionContext == null)
                throw new ArgumentNullException("executionContext"); 
#if	LOG
            Log("Execute on " + this.QualifiedName);
#endif
 
            // go figure out what the CAG needs to do
            this.CAGState = new ConditionedActivityGroupStateInfo(this); 
 
            if (EvaluateConditions(this, executionContext))
            { 
                // CAG until indicates we are done, so no children execute
                return ActivityExecutionStatus.Closed;
            }
 
            // start any pending activity required
            TriggerChildren(this, executionContext); 
            return this.ExecutionStatus; 
        }
 
        /// 
        /// Evaluate the conditions on the CAG
        /// 
        ///  
        /// 
        /// True if CAG is complete (UNTIL == true, or no UNTIL and no children execute), false otherwise 
        internal bool EvaluateConditions(ConditionedActivityGroup cag, ActivityExecutionContext context) 
        {
            Debug.Assert(cag != null); 
            Debug.Assert(context != null);
#if	LOG
            Log("EvaluateConditions on " + cag.QualifiedName);
            cag.CAGState.DumpState("Before EvaluateConditions"); 
#endif
            // if we've already decided to quit this CAG, don't do anything 
            if (cag.CAGState.Completed) 
                return false;
 
            // if the cag has an UNTIL condition, execute it
            if ((cag.UntilCondition != null) && cag.UntilCondition.Evaluate(cag, context))
            {
                // UNTIL condition says we're done, no need to look at children 
#if	LOG
                Log("Until condition is true"); 
#endif 
                return true;
            } 

            // until condition is false, so let's look at all children
            int childExecuting = 0;		// keep track of children executing
            Dictionary childrenStats = cag.CAGState.ChildrenStats; 
            foreach (Activity act in cag.EnabledActivities)
            { 
                // if we think the child is executing, do nothing 
                if (childrenStats[act.QualifiedName].State == CAGChildState.Excuting)
                { 
                    ++childExecuting;
                    continue;
                }
 
                // find the run-time activity
                Activity activity = GetRuntimeInitializedActivity(context, act); 
                // should it execute? 
                if (EvaluateChildConditions(cag, activity, context))
                { 
                    ++childExecuting;
                    childrenStats[act.QualifiedName].State = CAGChildState.Pending;
                }
            } 
#if	LOG
            cag.CAGState.DumpState("After EvaluateConditions"); 
#endif 

            // if any work to do, CAG not yet done 
            if (childExecuting > 0)
                return false;

            // CAG is quiet (nothing more to do) 
            // if specified an UNTIL condition but we have nothing to do
            if (cag.UntilCondition != null) 
            { 
#if	LOG
                Log("CAG quiet, but UNTIL condition is false, so error time"); 
#endif
                throw new InvalidOperationException(SR.GetString(SR.Error_CAGQuiet, cag.QualifiedName));
            }
#if	LOG 
            Log("CAG quiet");
#endif 
            return true; 
        }
 
        /// 
        /// Evaluate the While condition for a particular child of the CAG
        /// If no While condition, it becomes "execute once"
        ///  
        /// 
        ///  
        ///  
        /// 
        private bool EvaluateChildConditions(ConditionedActivityGroup cag, Activity child, ActivityExecutionContext context) 
        {
#if	LOG
            Log("EvaluateChildConditions on activity " + child.QualifiedName + " inside " + cag.QualifiedName);
#endif 
            // determine the result of the when condition (evaluate once if not specified)
            ConditionedActivityGroupStateInfo state = cag.CAGState; 
            try 
            {
                state.Testing = true; 
                ActivityCondition whenCondition = (ActivityCondition)child.GetValue(ConditionedActivityGroup.WhenConditionProperty);
                return (whenCondition != null)
                    ? whenCondition.Evaluate(child, context)
                    : (state.ChildrenStats[child.QualifiedName].ExecutedCount == 0); 
            }
            finally 
            { 
                state.Testing = false;
            } 
        }

        /// 
        /// Start any child activities that need to be run 
        /// 
        ///  
        ///  
        internal void TriggerChildren(ConditionedActivityGroup cag, ActivityExecutionContext context)
        { 
            Debug.Assert(cag != null);
            Debug.Assert(context != null);
#if	LOG
            Log("TriggerChildren on " + cag.QualifiedName); 
            cag.CAGState.DumpState("Before TriggerChildren");
#endif 
 
            Dictionary childrenStats = cag.CAGState.ChildrenStats;
            // until condition is false, so let's look at all children 
            foreach (Activity act in cag.EnabledActivities)
            {
                // do we think this child needs to run?
                if (childrenStats[act.QualifiedName].State != CAGChildState.Pending) 
                    continue;
 
                // find the run-time activity 
                Activity activity = GetRuntimeInitializedActivity(context, act);
                if (activity.ExecutionStatus == ActivityExecutionStatus.Initialized) 
                    ExecuteChild(cag, activity, context);
            }
#if	LOG
            cag.CAGState.DumpState("After TriggerChildren"); 
#endif
        } 
 
        private void ExecuteChild(ConditionedActivityGroup cag, Activity childActivity, ActivityExecutionContext context)
        { 
            Debug.Assert(cag != null);
            Debug.Assert(childActivity != null);
            Debug.Assert(context != null);
            Debug.Assert(childActivity.ExecutionStatus == ActivityExecutionStatus.Initialized); 
#if	LOG
            Log("ExecuteChild " + childActivity.QualifiedName + " inside " + cag.QualifiedName); 
#endif 
            ActivityExecutionContext childContext = GetChildExecutionContext(context, childActivity, true);
            cag.CAGState.ChildrenStats[childActivity.QualifiedName].State = CAGChildState.Excuting; 

            // subscribe for child closure
            childContext.Activity.RegisterForStatusChange(Activity.ClosedEvent, this);
 
            // execute child in inner context
            childContext.ExecuteActivity(childContext.Activity); 
        } 

        protected override ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext) 
        {
            if (executionContext == null)
                throw new ArgumentNullException("executionContext");
 
            // child activities are cancelled and could complete asynchronously.
            // if there was no asynchronous stuff then lets do the cag level cleanup 
 
            // if we are already done (or never started), then we are already closed
            if (this.CAGState == null) 
                return ActivityExecutionStatus.Closed;

            return Cleanup(this, executionContext) ? ActivityExecutionStatus.Closed : ActivityExecutionStatus.Canceling;
        } 

        #region IActivityEventListener Members 
        void IActivityEventListener.OnEvent(object sender, ActivityExecutionStatusChangedEventArgs e) 
        {
            this.HandleEvent(sender as ActivityExecutionContext, new SubscriptionEventArg(e, EventType.StatusChange)); 
        }
        #endregion

        internal void HandleEvent(ActivityExecutionContext context, SubscriptionEventArg e) 
        {
            if (context == null) 
                throw new ArgumentNullException("context"); 
            if (e == null)
                throw new ArgumentNullException("e"); 

            ConditionedActivityGroup cag = context.Activity as ConditionedActivityGroup;
            if (cag == null)
                throw new ArgumentException(SR.GetString(SR.Error_InvalidCAGActivityType), "activity"); 

            // Already done the cleanup from another child's signalling 
            if (cag.ExecutionStatus == ActivityExecutionStatus.Closed) 
                return;
 
            if (e.SubscriptionType != EventType.StatusChange)
            {
                // split into seperate test to keep FxCop happy (only place SubscriptionType used)
                Debug.Assert(false, "This CAG activity handler does not handle this event"); 
            }
            ActivityExecutionStatusChangedEventArgs args1 = (ActivityExecutionStatusChangedEventArgs)e.Args; 
#if	LOG 
            Log("HandleEvent for " + cag.QualifiedName);
            Log("event = " + e.ToString()); 
            Log("activity = " + args1.Activity.QualifiedName);
#endif

            bool timeToQuit = false; 

            // is this event is for an immediate child? 
            Debug.Assert(cag == args1.Activity.Parent, "Received event for non-child of CAG"); 
            Dictionary childrenStats = cag.CAGState.ChildrenStats;
 
            // it is possible that dynamic update has removed the child before we get the closed event
            // if that is the case, we don't need to update it's stats since it's not there
            if (childrenStats.ContainsKey(args1.Activity.QualifiedName))
            { 
                // update our state about the child
                if (args1.ExecutionStatus != ActivityExecutionStatus.Executing) 
                    childrenStats[args1.Activity.QualifiedName].State = CAGChildState.Idle; 

                // @undone: this will break if scopes move to "Delayed" closing after Completed. 
                if (args1.ExecutionStatus == ActivityExecutionStatus.Closed)
                    childrenStats[args1.Activity.QualifiedName].ExecutedCount++;

                try 
                {
                    // re-evaluate the conditions on any status change, as long as the CAG is still executing 
                    if (cag.ExecutionStatus == ActivityExecutionStatus.Executing) 
                        timeToQuit = EvaluateConditions(cag, context);
                } 
                finally
                {
                    // get rid of the child that just completed
                    // do this in the finally so that the child is cleaned up, 
                    // even if EvaluateConditions throws beause the CAG is stalled
                    CleanupChildAtClosure(context, args1.Activity); 
                } 
            }
            else 
            {
                // child has been removed
                // we still need to see if the CAG is done, provided we are still executing
                if (cag.ExecutionStatus == ActivityExecutionStatus.Executing) 
                    timeToQuit = EvaluateConditions(cag, context);
            } 
 
            // is the CAG just completed?
            if (timeToQuit) 
            {
                Cleanup(cag, context);
            }
            else if (cag.CAGState.Completed) 
            {
                // if the CAG is simply waiting for all children to complete, see if this is the last one 
                if (AllChildrenQuiet(cag, context)) 
                {
                    // Mark the CAG as closed, if it hasn't already been marked so. 
                    context.CloseActivity();
                }
            }
            else 
            {
                // CAG not done, so see if any children need to start 
                TriggerChildren(cag, context); 
            }
        } 

        internal bool Cleanup(ConditionedActivityGroup cag, ActivityExecutionContext context)
        {
            // the completion condition has fired, or we are canceling 
            // either way, we want to cleanup
            ConditionedActivityGroupStateInfo state = cag.CAGState; 
            state.Completed = true; 

            // cancel any children currently running 
            bool childrenActive = false;
            Dictionary childrenStats = state.ChildrenStats;
            foreach (Activity act in cag.EnabledActivities)
            { 
                // reset any Pending Execution for all child activity
                if (childrenStats[act.QualifiedName].State == CAGChildState.Pending) 
                    childrenStats[act.QualifiedName].State = CAGChildState.Idle; 

                // find the run-time activity 
                ActivityExecutionContext childContext = GetChildExecutionContext(context, act, false);
                if (childContext != null)
                {
                    // child must be running somewhere 
                    Activity activity = GetRuntimeInitializedActivity(context, act);
                    switch (activity.ExecutionStatus) 
                    { 
                        case ActivityExecutionStatus.Executing:
                            // schedule cancellation on child 
                            childContext.CancelActivity(activity);
                            childrenActive = true;
                            break;
 
                        case ActivityExecutionStatus.Canceling:
                        case ActivityExecutionStatus.Faulting: 
                            childrenActive = true; 
                            break;
 
                        case ActivityExecutionStatus.Closed:
                            CleanupChildAtClosure(context, activity);
                            break;
                        default: 
                            // unhook our handler
                            // others will be removed when we get the complete/cancel notification 
                            act.UnregisterForStatusChange(Activity.ClosedEvent, this); 
                            break;
                    } 
                }
            }

            // if the CAG is quiet, we are all done 
            if (!childrenActive)
                context.CloseActivity(); 
            return !childrenActive; 
        }
 
        private void CleanupChildAtClosure(ActivityExecutionContext context, Activity childActivity)
        {
            Debug.Assert(context != null);
            Debug.Assert(childActivity != null); 
            Debug.Assert(childActivity.ExecutionStatus == ActivityExecutionStatus.Closed);
 
            //UnSubsribe child closure of completed activity. 
            childActivity.UnregisterForStatusChange(Activity.ClosedEvent, this);
 
            //Dispose the execution context;
            ActivityExecutionContext childContext = GetChildExecutionContext(context, childActivity, false);
            ActivityExecutionContextManager contextManager = context.ExecutionContextManager;
            contextManager.CompleteExecutionContext(childContext); 
        }
 
        private Activity GetRuntimeInitializedActivity(ActivityExecutionContext context, Activity childActivity) 
        {
            ActivityExecutionContext childContext = GetChildExecutionContext(context, childActivity, false); 

            if (childContext == null)
                return childActivity;
 
            return childContext.Activity;
        } 
 
        private static ActivityExecutionContext GetChildExecutionContext(ActivityExecutionContext context, Activity childActivity, bool createIfNotExists)
        { 
            ActivityExecutionContextManager contextManager = context.ExecutionContextManager;
            ActivityExecutionContext childContext = contextManager.GetExecutionContext(childActivity);
            if (childContext != null)
                return childContext; 

            if (createIfNotExists) 
                childContext = contextManager.CreateExecutionContext(childActivity); 

            return childContext; 
        }

        bool AllChildrenQuiet(ConditionedActivityGroup cag, ActivityExecutionContext context)
        { 
            if (context == null)
                throw new ArgumentNullException("context"); 
 
            // if there are any execution contexts, 1 or more children still doing something
            foreach (ActivityExecutionContext activeContext in context.ExecutionContextManager.ExecutionContexts) 
            {
                if (cag.GetActivityByName(activeContext.Activity.QualifiedName, true) != null)
                {
                    return false; 
                }
            } 
 
            // no children
            return true; 
        }
    }

    internal sealed class SubscriptionEventArg : EventArgs 
    {
        private EventArgs _args; 
        private EventType _subscriptionType; 

        internal EventArgs Args 
        {
            get { return _args; }
        }
 
        internal EventType SubscriptionType
        { 
            get { return _subscriptionType; } 
        }
 
        public override string ToString()
        {
            return "SubscriptionEventArg(" + (_args == null ? "null" : _args.ToString()) + ")";
        } 

        internal SubscriptionEventArg(EventArgs args, EventType subType) 
        { 
            _args = args;
            _subscriptionType = subType; 
        }
    }

    [Serializable] 
    internal enum EventType : byte
    { 
        Timer = 0, 
        DataChange = 1,
        StatusChange = 2, 
        MessageArrival = 3,
        LockAcquisition = 4,
        InterActivity = 6,
    } 

    #region ConditionedActivityGroupStateInfo 
    [Serializable] 
    internal sealed class ConditionedActivityGroupStateInfo
    { 
        private bool completed;
        private bool testing;
        private Dictionary childActivityStats;
 
        #region Accessors
 
        internal bool Completed 
        {
            get { return this.completed; } 
            set { this.completed = value; }
        }

        internal bool Testing 
        {
            get { return testing; } 
            set { testing = value; } 
        }
 
        internal Dictionary ChildrenStats
        {
            get { return this.childActivityStats; }
        } 

        #endregion Accessors 
 
        internal ConditionedActivityGroupStateInfo(ConditionedActivityGroup cag)
        { 
            int len = cag.EnabledActivities.Count;
            this.childActivityStats = new Dictionary(len);
            foreach (Activity act in cag.EnabledActivities)
                this.childActivityStats[act.QualifiedName] = new CAGChildStats(); 
        }
 
#if	LOG 
        internal void DumpState(string message)
        { 
            Trace.WriteLine(message + " completed = " + Completed.ToString());
            foreach (string key in this.childActivityStats.Keys)
            {
                Trace.WriteLine(key + ": state = " + this.childActivityStats[key].State + ", performed = " + this.childActivityStats[key].ExecutedCount); 
            }
        } 
#endif 

    } 

    [Serializable]
    internal enum CAGChildState : byte
    { 
        Idle,
        Pending, 
        Excuting 
    }
 
    [Serializable]
    internal class CAGChildStats
    {
        internal int ExecutedCount = 0; 
        internal CAGChildState State = CAGChildState.Idle;
        internal CAGChildStats() 
        { } 
    }
    #endregion 

        #endregion

 
    #region Validator
    internal sealed class ConditionedActivityGroupValidator : CompositeActivityValidator 
    { 
        public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
        { 
            ValidationErrorCollection validationErrors = base.Validate(manager, obj);

            ConditionedActivityGroup conditionedActivityGroup = obj as ConditionedActivityGroup;
            if (conditionedActivityGroup == null) 
                throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(ConditionedActivityGroup).FullName), "obj");
 
            return validationErrors; 
        }
 
        public override ValidationError ValidateActivityChange(Activity activity, ActivityChangeAction action)
        {
            if (activity == null)
                throw new ArgumentNullException("activity"); 
            if (action == null)
                throw new ArgumentNullException("action"); 
 
            if (activity.ExecutionStatus != ActivityExecutionStatus.Initialized &&
                activity.ExecutionStatus != ActivityExecutionStatus.Executing && 
                activity.ExecutionStatus != ActivityExecutionStatus.Closed)
            {
                return new ValidationError(SR.GetString(SR.Error_DynamicActivity2, activity.QualifiedName, activity.ExecutionStatus, activity.GetType().FullName), ErrorNumbers.Error_DynamicActivity2);
            } 

            // if we are currently executing, make sure that we are not changing something already running 
            // removed since changes mean that the child activity is going to get validated anyway 

            return null; 
        }
    }
    #endregion
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
namespace System.Workflow.Activities 
{
    #region Imports

    using System; 
    using System.Diagnostics;
    using System.Xml; 
    using System.CodeDom; 
    using System.Drawing;
    using System.Collections; 
    using System.Windows.Forms;
    using System.ComponentModel;
    using System.Drawing.Drawing2D;
    using System.Collections.Generic; 
    using System.Windows.Forms.Design;
    using System.ComponentModel.Design; 
    using System.Workflow.ComponentModel; 
    using System.Workflow.ComponentModel.Design;
    using System.ComponentModel.Design.Serialization; 
    using System.Workflow.ComponentModel.Compiler;
    using System.Workflow.Runtime.DebugEngine;
    using System.Workflow.Activities.Common;
 
    #endregion
 
    [SRDescription(SR.ConstrainedGroupActivityDescription)] 
    [ToolboxItem(typeof(ActivityToolboxItem))]
    [Designer(typeof(ConditionedActivityGroupDesigner), typeof(IDesigner))] 
    [ToolboxBitmap(typeof(ConditionedActivityGroup), "Resources.cag.png")]
    [ActivityValidator(typeof(ConditionedActivityGroupValidator))]
    [SRCategory(SR.Standard)]
    [WorkflowDebuggerSteppingAttribute(WorkflowDebuggerSteppingOption.Concurrent)] 
    public sealed class ConditionedActivityGroup : CompositeActivity, IActivityEventListener
    { 
        //Attached properties provided to the children 
        public static readonly DependencyProperty WhenConditionProperty = DependencyProperty.RegisterAttached("WhenCondition", typeof(ActivityCondition), typeof(ConditionedActivityGroup), new PropertyMetadata(DependencyPropertyOptions.Metadata), typeof(WhenUnlessConditionDynamicPropertyValidator));
 
        // metadata properties go here
        public static readonly DependencyProperty UntilConditionProperty = DependencyProperty.Register("UntilCondition", typeof(ActivityCondition), typeof(ConditionedActivityGroup), new PropertyMetadata(DependencyPropertyOptions.Metadata));

        #region Constructors 

        public ConditionedActivityGroup() 
        { 
        }
 
        public ConditionedActivityGroup(string name)
            : base(name)
        {
        } 

        #endregion 
 
        // WhenConditionProperty Get and Set Accessors
        public static object GetWhenCondition(object dependencyObject) 
        {
            if (dependencyObject == null)
                throw new ArgumentNullException("dependencyObject");
            if(!(dependencyObject is DependencyObject)) 
                throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(DependencyObject).FullName), "dependencyObject");
 
            return (dependencyObject as DependencyObject).GetValue(WhenConditionProperty); 
        }
 
        public static void SetWhenCondition(object dependencyObject, object value)
        {
            if (dependencyObject == null)
                throw new ArgumentNullException("dependencyObject"); 
            if (!(dependencyObject is DependencyObject))
                throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(DependencyObject).FullName), "dependencyObject"); 
 
            (dependencyObject as DependencyObject).SetValue(WhenConditionProperty, value);
        } 

        [SRCategory(SR.Conditions)]
        [SRDescription(SR.UntilConditionDescr)]
        [DefaultValue(null)] 
        public ActivityCondition UntilCondition
        { 
            get 
            {
                return base.GetValue(UntilConditionProperty) as ActivityCondition; 
            }
            set
            {
                base.SetValue(UntilConditionProperty, value); 
            }
        } 
 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        private Activity GetDynamicActivity(Activity childActivity)
        {
            if (childActivity == null)
                throw new ArgumentNullException("childActivity"); 

            if (!this.EnabledActivities.Contains(childActivity)) 
                throw new ArgumentException(SR.GetString(SR.Error_CAGChildNotFound, childActivity.QualifiedName, this.QualifiedName), "childActivity"); 
            else
            { 
                Activity[] dynamicChildActivity = this.GetDynamicActivities(childActivity);

                if (dynamicChildActivity.Length != 0)
                    return dynamicChildActivity[0]; 
                else
                    return null; 
            } 
        }
 
        public Activity GetDynamicActivity(String childActivityName)
        {
            if (childActivityName == null)
                throw new ArgumentNullException("childActivityName"); 

            Activity childActivity = null; 
 
            for (int i = 0; i < this.EnabledActivities.Count; ++i)
            { 
                if (this.EnabledActivities[i].QualifiedName.Equals(childActivityName))
                {
                    childActivity = this.EnabledActivities[i];
                    break; 
                }
            } 
 
            if (childActivity != null)
                return GetDynamicActivity(childActivity); 

            throw new ArgumentException(SR.GetString(SR.Error_CAGChildNotFound, childActivityName, this.QualifiedName), "childActivityName");
        }
 
        public int GetChildActivityExecutedCount(Activity child)
        { 
            if (child == null) 
                throw new ArgumentNullException("child");
 
            ConditionedActivityGroupStateInfo conditionedInfo = this.CAGState;

            if (conditionedInfo == null)
            { 
                throw new InvalidOperationException(SR.GetString(SR.Error_CAGNotExecuting, this.QualifiedName));
            } 
 
            if (!conditionedInfo.ChildrenStats.ContainsKey(child.QualifiedName))
            { 
                throw new ArgumentException(SR.GetString(SR.Error_CAGChildNotFound, child.QualifiedName, this.QualifiedName), "child");
            }
            else
            { 
                return conditionedInfo.ChildrenStats[child.QualifiedName].ExecutedCount;
            } 
        } 

        private sealed class WhenUnlessConditionDynamicPropertyValidator : Validator 
        {
            public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
            {
                ValidationErrorCollection validationErrors = ValidationHelpers.ValidateObject(manager, obj); 

                if (validationErrors.Count == 0) 
                { 
                    Activity activity = manager.Context[typeof(Activity)] as Activity;
                    if (activity == null) 
                        throw new InvalidOperationException(SR.GetString(SR.Error_ContextStackItemMissing, typeof(Activity).Name));

                    CodeCondition codeCondition = obj as CodeCondition;
                    if (codeCondition != null && codeCondition.IsBindingSet(CodeCondition.ConditionEvent)) 
                    {
                        ActivityBind activityBind = codeCondition.GetBinding(CodeCondition.ConditionEvent) as ActivityBind; 
                        if (activityBind != null) 
                        {
                            Activity contextActivity = Helpers.ParseActivityForBind(activity, activityBind.Name); 
                            if (contextActivity != null && Helpers.IsChildActivity(activity.Parent, contextActivity))
                            {
                                string propertyName = GetFullPropertyName(manager);
                                ValidationError error = new ValidationError(SR.GetString(SR.Error_NestedConstrainedGroupConditions, propertyName), ErrorNumbers.Error_NestedConstrainedGroupConditions); 
                                error.PropertyName = propertyName;
                                validationErrors.Add(error); 
                            } 
                        }
                    } 
                }

                return validationErrors;
            } 
        }
 
        #region Runtime Internal Dependency Property 
        static DependencyProperty CAGStateProperty = DependencyProperty.Register("CAGState", typeof(ConditionedActivityGroupStateInfo), typeof(ConditionedActivityGroup));
 
        internal ConditionedActivityGroupStateInfo CAGState
        {
            get
            { 
                return (ConditionedActivityGroupStateInfo)base.GetValue(CAGStateProperty);
            } 
            set 
            {
                base.SetValue(CAGStateProperty, value); 
            }
        }
        #endregion
 
        protected override void OnClosed(IServiceProvider provider)
        { 
            base.RemoveProperty(ConditionedActivityGroup.CAGStateProperty); 
        }
 
        #region Workflow Changes Overrides
        protected override void OnActivityChangeAdd(ActivityExecutionContext executionContext, Activity addedActivity)
        {
            if (executionContext == null) 
                throw new ArgumentNullException("executionContext");
            if (addedActivity == null) 
                throw new ArgumentNullException("addedActivity"); 

            if (!addedActivity.Enabled) 
                return;

            ConditionedActivityGroup currentActivity = executionContext.Activity as ConditionedActivityGroup;
            Debug.Assert(currentActivity != null); 

            ConditionedActivityGroupStateInfo state = currentActivity.CAGState; 
            if (currentActivity.ExecutionStatus == ActivityExecutionStatus.Executing && state != null) 
            {
                Debug.Assert(currentActivity == addedActivity.Parent, "Attempting to add wrong activity to CAG"); 
                state.ChildrenStats[addedActivity.QualifiedName] = new CAGChildStats();
            }
        }
 
        protected override void OnActivityChangeRemove(ActivityExecutionContext executionContext, Activity removedActivity)
        { 
            if (executionContext == null) 
                throw new ArgumentNullException("executionContext");
            if (removedActivity == null) 
                throw new ArgumentNullException("removedActivity");

            if (!removedActivity.Enabled)
                return; 

            ConditionedActivityGroup cag = executionContext.Activity as ConditionedActivityGroup; 
            Debug.Assert(cag != null); 

            // find out the status of the cag 

            ConditionedActivityGroupStateInfo state = cag.CAGState;
            if ((cag.ExecutionStatus == ActivityExecutionStatus.Executing) && (state != null))
            { 
                state.ChildrenStats.Remove(removedActivity.QualifiedName);
            } 
        } 

        protected override void OnWorkflowChangesCompleted(ActivityExecutionContext executionContext) 
        {
            if (executionContext == null)
                throw new ArgumentNullException("executionContext");
 
            // find out the status of the cag
            ConditionedActivityGroup currentActivity = executionContext.Activity as ConditionedActivityGroup; 
 
            // if CAG is executing... fire the conditions on the net result
            if (currentActivity.ExecutionStatus == ActivityExecutionStatus.Executing) 
            {
                // but hold on, a derived cag could be applying model changes before it
                // "really" starts executing the activities. In that case it will evaluate
                // the conditions later, at the appropriate time. 
                ConditionedActivityGroupStateInfo state = currentActivity.CAGState;
                if ((state != null) && (!state.Testing)) 
                { 
                    // fire away...  fire away... said the CAG
                    if (this.EvaluateConditions(currentActivity, executionContext)) 
                    {
                        // CAG until indicates we are done, so no children execute
                        this.Cleanup(currentActivity, executionContext);
                    } 
                    else
                    { 
                        // start any pending activity required 
                        this.TriggerChildren(currentActivity, executionContext);
                    } 
                }
            }
        }
 
        #endregion
 
        #region Execution Implementation 
#if	LOG
        private static void Log(string message) 
        {
            Trace.WriteLine(message);
        }
#endif 

        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) 
        { 
            if (executionContext == null)
                throw new ArgumentNullException("executionContext"); 
#if	LOG
            Log("Execute on " + this.QualifiedName);
#endif
 
            // go figure out what the CAG needs to do
            this.CAGState = new ConditionedActivityGroupStateInfo(this); 
 
            if (EvaluateConditions(this, executionContext))
            { 
                // CAG until indicates we are done, so no children execute
                return ActivityExecutionStatus.Closed;
            }
 
            // start any pending activity required
            TriggerChildren(this, executionContext); 
            return this.ExecutionStatus; 
        }
 
        /// 
        /// Evaluate the conditions on the CAG
        /// 
        ///  
        /// 
        /// True if CAG is complete (UNTIL == true, or no UNTIL and no children execute), false otherwise 
        internal bool EvaluateConditions(ConditionedActivityGroup cag, ActivityExecutionContext context) 
        {
            Debug.Assert(cag != null); 
            Debug.Assert(context != null);
#if	LOG
            Log("EvaluateConditions on " + cag.QualifiedName);
            cag.CAGState.DumpState("Before EvaluateConditions"); 
#endif
            // if we've already decided to quit this CAG, don't do anything 
            if (cag.CAGState.Completed) 
                return false;
 
            // if the cag has an UNTIL condition, execute it
            if ((cag.UntilCondition != null) && cag.UntilCondition.Evaluate(cag, context))
            {
                // UNTIL condition says we're done, no need to look at children 
#if	LOG
                Log("Until condition is true"); 
#endif 
                return true;
            } 

            // until condition is false, so let's look at all children
            int childExecuting = 0;		// keep track of children executing
            Dictionary childrenStats = cag.CAGState.ChildrenStats; 
            foreach (Activity act in cag.EnabledActivities)
            { 
                // if we think the child is executing, do nothing 
                if (childrenStats[act.QualifiedName].State == CAGChildState.Excuting)
                { 
                    ++childExecuting;
                    continue;
                }
 
                // find the run-time activity
                Activity activity = GetRuntimeInitializedActivity(context, act); 
                // should it execute? 
                if (EvaluateChildConditions(cag, activity, context))
                { 
                    ++childExecuting;
                    childrenStats[act.QualifiedName].State = CAGChildState.Pending;
                }
            } 
#if	LOG
            cag.CAGState.DumpState("After EvaluateConditions"); 
#endif 

            // if any work to do, CAG not yet done 
            if (childExecuting > 0)
                return false;

            // CAG is quiet (nothing more to do) 
            // if specified an UNTIL condition but we have nothing to do
            if (cag.UntilCondition != null) 
            { 
#if	LOG
                Log("CAG quiet, but UNTIL condition is false, so error time"); 
#endif
                throw new InvalidOperationException(SR.GetString(SR.Error_CAGQuiet, cag.QualifiedName));
            }
#if	LOG 
            Log("CAG quiet");
#endif 
            return true; 
        }
 
        /// 
        /// Evaluate the While condition for a particular child of the CAG
        /// If no While condition, it becomes "execute once"
        ///  
        /// 
        ///  
        ///  
        /// 
        private bool EvaluateChildConditions(ConditionedActivityGroup cag, Activity child, ActivityExecutionContext context) 
        {
#if	LOG
            Log("EvaluateChildConditions on activity " + child.QualifiedName + " inside " + cag.QualifiedName);
#endif 
            // determine the result of the when condition (evaluate once if not specified)
            ConditionedActivityGroupStateInfo state = cag.CAGState; 
            try 
            {
                state.Testing = true; 
                ActivityCondition whenCondition = (ActivityCondition)child.GetValue(ConditionedActivityGroup.WhenConditionProperty);
                return (whenCondition != null)
                    ? whenCondition.Evaluate(child, context)
                    : (state.ChildrenStats[child.QualifiedName].ExecutedCount == 0); 
            }
            finally 
            { 
                state.Testing = false;
            } 
        }

        /// 
        /// Start any child activities that need to be run 
        /// 
        ///  
        ///  
        internal void TriggerChildren(ConditionedActivityGroup cag, ActivityExecutionContext context)
        { 
            Debug.Assert(cag != null);
            Debug.Assert(context != null);
#if	LOG
            Log("TriggerChildren on " + cag.QualifiedName); 
            cag.CAGState.DumpState("Before TriggerChildren");
#endif 
 
            Dictionary childrenStats = cag.CAGState.ChildrenStats;
            // until condition is false, so let's look at all children 
            foreach (Activity act in cag.EnabledActivities)
            {
                // do we think this child needs to run?
                if (childrenStats[act.QualifiedName].State != CAGChildState.Pending) 
                    continue;
 
                // find the run-time activity 
                Activity activity = GetRuntimeInitializedActivity(context, act);
                if (activity.ExecutionStatus == ActivityExecutionStatus.Initialized) 
                    ExecuteChild(cag, activity, context);
            }
#if	LOG
            cag.CAGState.DumpState("After TriggerChildren"); 
#endif
        } 
 
        private void ExecuteChild(ConditionedActivityGroup cag, Activity childActivity, ActivityExecutionContext context)
        { 
            Debug.Assert(cag != null);
            Debug.Assert(childActivity != null);
            Debug.Assert(context != null);
            Debug.Assert(childActivity.ExecutionStatus == ActivityExecutionStatus.Initialized); 
#if	LOG
            Log("ExecuteChild " + childActivity.QualifiedName + " inside " + cag.QualifiedName); 
#endif 
            ActivityExecutionContext childContext = GetChildExecutionContext(context, childActivity, true);
            cag.CAGState.ChildrenStats[childActivity.QualifiedName].State = CAGChildState.Excuting; 

            // subscribe for child closure
            childContext.Activity.RegisterForStatusChange(Activity.ClosedEvent, this);
 
            // execute child in inner context
            childContext.ExecuteActivity(childContext.Activity); 
        } 

        protected override ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext) 
        {
            if (executionContext == null)
                throw new ArgumentNullException("executionContext");
 
            // child activities are cancelled and could complete asynchronously.
            // if there was no asynchronous stuff then lets do the cag level cleanup 
 
            // if we are already done (or never started), then we are already closed
            if (this.CAGState == null) 
                return ActivityExecutionStatus.Closed;

            return Cleanup(this, executionContext) ? ActivityExecutionStatus.Closed : ActivityExecutionStatus.Canceling;
        } 

        #region IActivityEventListener Members 
        void IActivityEventListener.OnEvent(object sender, ActivityExecutionStatusChangedEventArgs e) 
        {
            this.HandleEvent(sender as ActivityExecutionContext, new SubscriptionEventArg(e, EventType.StatusChange)); 
        }
        #endregion

        internal void HandleEvent(ActivityExecutionContext context, SubscriptionEventArg e) 
        {
            if (context == null) 
                throw new ArgumentNullException("context"); 
            if (e == null)
                throw new ArgumentNullException("e"); 

            ConditionedActivityGroup cag = context.Activity as ConditionedActivityGroup;
            if (cag == null)
                throw new ArgumentException(SR.GetString(SR.Error_InvalidCAGActivityType), "activity"); 

            // Already done the cleanup from another child's signalling 
            if (cag.ExecutionStatus == ActivityExecutionStatus.Closed) 
                return;
 
            if (e.SubscriptionType != EventType.StatusChange)
            {
                // split into seperate test to keep FxCop happy (only place SubscriptionType used)
                Debug.Assert(false, "This CAG activity handler does not handle this event"); 
            }
            ActivityExecutionStatusChangedEventArgs args1 = (ActivityExecutionStatusChangedEventArgs)e.Args; 
#if	LOG 
            Log("HandleEvent for " + cag.QualifiedName);
            Log("event = " + e.ToString()); 
            Log("activity = " + args1.Activity.QualifiedName);
#endif

            bool timeToQuit = false; 

            // is this event is for an immediate child? 
            Debug.Assert(cag == args1.Activity.Parent, "Received event for non-child of CAG"); 
            Dictionary childrenStats = cag.CAGState.ChildrenStats;
 
            // it is possible that dynamic update has removed the child before we get the closed event
            // if that is the case, we don't need to update it's stats since it's not there
            if (childrenStats.ContainsKey(args1.Activity.QualifiedName))
            { 
                // update our state about the child
                if (args1.ExecutionStatus != ActivityExecutionStatus.Executing) 
                    childrenStats[args1.Activity.QualifiedName].State = CAGChildState.Idle; 

                // @undone: this will break if scopes move to "Delayed" closing after Completed. 
                if (args1.ExecutionStatus == ActivityExecutionStatus.Closed)
                    childrenStats[args1.Activity.QualifiedName].ExecutedCount++;

                try 
                {
                    // re-evaluate the conditions on any status change, as long as the CAG is still executing 
                    if (cag.ExecutionStatus == ActivityExecutionStatus.Executing) 
                        timeToQuit = EvaluateConditions(cag, context);
                } 
                finally
                {
                    // get rid of the child that just completed
                    // do this in the finally so that the child is cleaned up, 
                    // even if EvaluateConditions throws beause the CAG is stalled
                    CleanupChildAtClosure(context, args1.Activity); 
                } 
            }
            else 
            {
                // child has been removed
                // we still need to see if the CAG is done, provided we are still executing
                if (cag.ExecutionStatus == ActivityExecutionStatus.Executing) 
                    timeToQuit = EvaluateConditions(cag, context);
            } 
 
            // is the CAG just completed?
            if (timeToQuit) 
            {
                Cleanup(cag, context);
            }
            else if (cag.CAGState.Completed) 
            {
                // if the CAG is simply waiting for all children to complete, see if this is the last one 
                if (AllChildrenQuiet(cag, context)) 
                {
                    // Mark the CAG as closed, if it hasn't already been marked so. 
                    context.CloseActivity();
                }
            }
            else 
            {
                // CAG not done, so see if any children need to start 
                TriggerChildren(cag, context); 
            }
        } 

        internal bool Cleanup(ConditionedActivityGroup cag, ActivityExecutionContext context)
        {
            // the completion condition has fired, or we are canceling 
            // either way, we want to cleanup
            ConditionedActivityGroupStateInfo state = cag.CAGState; 
            state.Completed = true; 

            // cancel any children currently running 
            bool childrenActive = false;
            Dictionary childrenStats = state.ChildrenStats;
            foreach (Activity act in cag.EnabledActivities)
            { 
                // reset any Pending Execution for all child activity
                if (childrenStats[act.QualifiedName].State == CAGChildState.Pending) 
                    childrenStats[act.QualifiedName].State = CAGChildState.Idle; 

                // find the run-time activity 
                ActivityExecutionContext childContext = GetChildExecutionContext(context, act, false);
                if (childContext != null)
                {
                    // child must be running somewhere 
                    Activity activity = GetRuntimeInitializedActivity(context, act);
                    switch (activity.ExecutionStatus) 
                    { 
                        case ActivityExecutionStatus.Executing:
                            // schedule cancellation on child 
                            childContext.CancelActivity(activity);
                            childrenActive = true;
                            break;
 
                        case ActivityExecutionStatus.Canceling:
                        case ActivityExecutionStatus.Faulting: 
                            childrenActive = true; 
                            break;
 
                        case ActivityExecutionStatus.Closed:
                            CleanupChildAtClosure(context, activity);
                            break;
                        default: 
                            // unhook our handler
                            // others will be removed when we get the complete/cancel notification 
                            act.UnregisterForStatusChange(Activity.ClosedEvent, this); 
                            break;
                    } 
                }
            }

            // if the CAG is quiet, we are all done 
            if (!childrenActive)
                context.CloseActivity(); 
            return !childrenActive; 
        }
 
        private void CleanupChildAtClosure(ActivityExecutionContext context, Activity childActivity)
        {
            Debug.Assert(context != null);
            Debug.Assert(childActivity != null); 
            Debug.Assert(childActivity.ExecutionStatus == ActivityExecutionStatus.Closed);
 
            //UnSubsribe child closure of completed activity. 
            childActivity.UnregisterForStatusChange(Activity.ClosedEvent, this);
 
            //Dispose the execution context;
            ActivityExecutionContext childContext = GetChildExecutionContext(context, childActivity, false);
            ActivityExecutionContextManager contextManager = context.ExecutionContextManager;
            contextManager.CompleteExecutionContext(childContext); 
        }
 
        private Activity GetRuntimeInitializedActivity(ActivityExecutionContext context, Activity childActivity) 
        {
            ActivityExecutionContext childContext = GetChildExecutionContext(context, childActivity, false); 

            if (childContext == null)
                return childActivity;
 
            return childContext.Activity;
        } 
 
        private static ActivityExecutionContext GetChildExecutionContext(ActivityExecutionContext context, Activity childActivity, bool createIfNotExists)
        { 
            ActivityExecutionContextManager contextManager = context.ExecutionContextManager;
            ActivityExecutionContext childContext = contextManager.GetExecutionContext(childActivity);
            if (childContext != null)
                return childContext; 

            if (createIfNotExists) 
                childContext = contextManager.CreateExecutionContext(childActivity); 

            return childContext; 
        }

        bool AllChildrenQuiet(ConditionedActivityGroup cag, ActivityExecutionContext context)
        { 
            if (context == null)
                throw new ArgumentNullException("context"); 
 
            // if there are any execution contexts, 1 or more children still doing something
            foreach (ActivityExecutionContext activeContext in context.ExecutionContextManager.ExecutionContexts) 
            {
                if (cag.GetActivityByName(activeContext.Activity.QualifiedName, true) != null)
                {
                    return false; 
                }
            } 
 
            // no children
            return true; 
        }
    }

    internal sealed class SubscriptionEventArg : EventArgs 
    {
        private EventArgs _args; 
        private EventType _subscriptionType; 

        internal EventArgs Args 
        {
            get { return _args; }
        }
 
        internal EventType SubscriptionType
        { 
            get { return _subscriptionType; } 
        }
 
        public override string ToString()
        {
            return "SubscriptionEventArg(" + (_args == null ? "null" : _args.ToString()) + ")";
        } 

        internal SubscriptionEventArg(EventArgs args, EventType subType) 
        { 
            _args = args;
            _subscriptionType = subType; 
        }
    }

    [Serializable] 
    internal enum EventType : byte
    { 
        Timer = 0, 
        DataChange = 1,
        StatusChange = 2, 
        MessageArrival = 3,
        LockAcquisition = 4,
        InterActivity = 6,
    } 

    #region ConditionedActivityGroupStateInfo 
    [Serializable] 
    internal sealed class ConditionedActivityGroupStateInfo
    { 
        private bool completed;
        private bool testing;
        private Dictionary childActivityStats;
 
        #region Accessors
 
        internal bool Completed 
        {
            get { return this.completed; } 
            set { this.completed = value; }
        }

        internal bool Testing 
        {
            get { return testing; } 
            set { testing = value; } 
        }
 
        internal Dictionary ChildrenStats
        {
            get { return this.childActivityStats; }
        } 

        #endregion Accessors 
 
        internal ConditionedActivityGroupStateInfo(ConditionedActivityGroup cag)
        { 
            int len = cag.EnabledActivities.Count;
            this.childActivityStats = new Dictionary(len);
            foreach (Activity act in cag.EnabledActivities)
                this.childActivityStats[act.QualifiedName] = new CAGChildStats(); 
        }
 
#if	LOG 
        internal void DumpState(string message)
        { 
            Trace.WriteLine(message + " completed = " + Completed.ToString());
            foreach (string key in this.childActivityStats.Keys)
            {
                Trace.WriteLine(key + ": state = " + this.childActivityStats[key].State + ", performed = " + this.childActivityStats[key].ExecutedCount); 
            }
        } 
#endif 

    } 

    [Serializable]
    internal enum CAGChildState : byte
    { 
        Idle,
        Pending, 
        Excuting 
    }
 
    [Serializable]
    internal class CAGChildStats
    {
        internal int ExecutedCount = 0; 
        internal CAGChildState State = CAGChildState.Idle;
        internal CAGChildStats() 
        { } 
    }
    #endregion 

        #endregion

 
    #region Validator
    internal sealed class ConditionedActivityGroupValidator : CompositeActivityValidator 
    { 
        public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
        { 
            ValidationErrorCollection validationErrors = base.Validate(manager, obj);

            ConditionedActivityGroup conditionedActivityGroup = obj as ConditionedActivityGroup;
            if (conditionedActivityGroup == null) 
                throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(ConditionedActivityGroup).FullName), "obj");
 
            return validationErrors; 
        }
 
        public override ValidationError ValidateActivityChange(Activity activity, ActivityChangeAction action)
        {
            if (activity == null)
                throw new ArgumentNullException("activity"); 
            if (action == null)
                throw new ArgumentNullException("action"); 
 
            if (activity.ExecutionStatus != ActivityExecutionStatus.Initialized &&
                activity.ExecutionStatus != ActivityExecutionStatus.Executing && 
                activity.ExecutionStatus != ActivityExecutionStatus.Closed)
            {
                return new ValidationError(SR.GetString(SR.Error_DynamicActivity2, activity.QualifiedName, activity.ExecutionStatus, activity.GetType().FullName), ErrorNumbers.Error_DynamicActivity2);
            } 

            // if we are currently executing, make sure that we are not changing something already running 
            // removed since changes mean that the child activity is going to get validated anyway 

            return null; 
        }
    }
    #endregion
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK