File: AuthoringOM\ActivityExecutionContextCollection.cs
Project: ndp\cdf\src\WF\Common\System.Workflow.ComponentModel.csproj (System.Workflow.ComponentModel)
#pragma warning disable 1634, 1691
 
namespace System.Workflow.ComponentModel
{
    #region Imports
 
    using System;
    using System.Diagnostics;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Workflow.ComponentModel.Design;
    using System.Runtime.Serialization;
    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Workflow.ComponentModel.Serialization;
    #endregion
 
    [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
    public sealed class ActivityExecutionContextManager
    {
        #region Data members and constructor
 
        private ActivityExecutionContext ownerContext = null;
        private List<ActivityExecutionContext> executionContexts = new List<ActivityExecutionContext>();
 
        internal ActivityExecutionContextManager(ActivityExecutionContext ownerContext)
        {
            this.ownerContext = ownerContext;
 
            // Populate the child collection.
            IList<Activity> activeContexts = (IList<Activity>)this.ownerContext.Activity.ContextActivity.GetValue(Activity.ActiveExecutionContextsProperty);
            if (activeContexts != null)
            {
                foreach (Activity activeContextActivity in activeContexts)
                    this.executionContexts.Add(new ActivityExecutionContext(activeContextActivity));
            }
        }
 
        #endregion
 
        #region Public members
 
        public ReadOnlyCollection<ActivityExecutionContext> ExecutionContexts
        {
            get
            {
                if (this.ownerContext == null)
#pragma warning suppress 56503
                    throw new ObjectDisposedException("ActivityExecutionContextManager");
 
                return new ReadOnlyCollection<ActivityExecutionContext>(this.executionContexts);
            }
        }
 
        public ActivityExecutionContext CreateExecutionContext(Activity activity)
        {
            if (this.ownerContext == null)
                throw new ObjectDisposedException("ActivityExecutionContextManager");
 
            if (activity == null)
                throw new ArgumentNullException("activity");
 
            if (!this.ownerContext.IsValidChild(activity, true))
                throw new ArgumentException(SR.GetString(SR.AEC_InvalidActivity), "activity");
 
            Activity copiedActivity = activity.Clone();
            ((IDependencyObjectAccessor)copiedActivity).InitializeInstanceForRuntime(this.ownerContext.Activity.WorkflowCoreRuntime);
 
            //Reset the cloned tree for execution.
            Queue<Activity> activityQueue = new Queue<Activity>();
            activityQueue.Enqueue(copiedActivity);
 
            while (activityQueue.Count != 0)
            {
                Activity clonedActivity = activityQueue.Dequeue();
                if (clonedActivity.ExecutionStatus != ActivityExecutionStatus.Initialized)
                {
                    clonedActivity.ResetAllKnownDependencyProperties();
                    CompositeActivity compositeActivity = clonedActivity as CompositeActivity;
 
                    if (compositeActivity != null)
                    {
                        for (int i = 0; i < compositeActivity.EnabledActivities.Count; ++i)
                        {
                            activityQueue.Enqueue(compositeActivity.EnabledActivities[i]);
                        }
 
                        ISupportAlternateFlow alternateFlow = compositeActivity as ISupportAlternateFlow;
 
                        if (alternateFlow != null)
                        {
                            for (int i = 0; i < alternateFlow.AlternateFlowActivities.Count; ++i)
                            {
                                activityQueue.Enqueue(alternateFlow.AlternateFlowActivities[i]);
                            }
                        }
                    }
                }
            }
 
            // get active context activities and add it to this one
            IList<Activity> activeContexts = (IList<Activity>)this.ownerContext.Activity.ContextActivity.GetValue(Activity.ActiveExecutionContextsProperty);
            if (activeContexts == null)
            {
                activeContexts = new List<Activity>();
                this.ownerContext.Activity.ContextActivity.SetValue(Activity.ActiveExecutionContextsProperty, activeContexts);
            }
            activeContexts.Add(copiedActivity);
 
            // prepare the copied activity as a context activity
            ActivityExecutionContextInfo contextInfo = new ActivityExecutionContextInfo(activity.QualifiedName, this.ownerContext.WorkflowCoreRuntime.GetNewContextActivityId(), Guid.NewGuid(), this.ownerContext.ContextId);
            copiedActivity.SetValue(Activity.ActivityExecutionContextInfoProperty, contextInfo);
            copiedActivity.SetValue(Activity.ActivityContextGuidProperty, contextInfo.ContextGuid);
            ActivityExecutionContext newExecutionContext = null;
            try
            {
                // inform workflow runtime
                this.ownerContext.Activity.WorkflowCoreRuntime.RegisterContextActivity(copiedActivity);
 
                // return the new context
                newExecutionContext = new ActivityExecutionContext(copiedActivity);
                this.executionContexts.Add(newExecutionContext);
                newExecutionContext.InitializeActivity(newExecutionContext.Activity);
                return newExecutionContext;
            }
            catch (Exception)
            {
                if (newExecutionContext != null)
                {
                    this.CompleteExecutionContext(newExecutionContext);
                }
                else
                {
                    activeContexts.Remove(copiedActivity);
                }
                throw;
            }
        }
 
        public void CompleteExecutionContext(ActivityExecutionContext childContext)
        {
            if (this.ownerContext == null)
                throw new ObjectDisposedException("ActivityExecutionContextManager");
 
            CompleteExecutionContext(childContext, false);
        }
 
        public void CompleteExecutionContext(ActivityExecutionContext childContext, bool forcePersist)
        {
            if (this.ownerContext == null)
                throw new ObjectDisposedException("ActivityExecutionContextManager");
 
            if (childContext == null)
                throw new ArgumentNullException("childContext");
 
            if (childContext.Activity == null)
                throw new ArgumentException("childContext", SR.GetString(SR.Error_MissingActivityProperty));
 
            if (childContext.Activity.ContextActivity == null)
                throw new ArgumentException("childContext", SR.GetString(SR.Error_MissingContextActivityProperty));
 
            if (!this.executionContexts.Contains(childContext))
                throw new ArgumentException();
 
            if (childContext.Activity.ContextActivity.ExecutionStatus != ActivityExecutionStatus.Closed && childContext.Activity.ContextActivity.ExecutionStatus != ActivityExecutionStatus.Initialized)
                throw new InvalidOperationException(SR.GetString(System.Globalization.CultureInfo.CurrentCulture, SR.Error_CannotCompleteContext));
 
            // make sure that this is in the active contexts collections
            ActivityExecutionContextInfo childContextInfo = childContext.Activity.ContextActivity.GetValue(Activity.ActivityExecutionContextInfoProperty) as ActivityExecutionContextInfo;
            IList<Activity> activeContexts = (IList<Activity>)this.ownerContext.Activity.ContextActivity.GetValue(Activity.ActiveExecutionContextsProperty);
            if (activeContexts == null || !activeContexts.Contains(childContext.Activity.ContextActivity))
                throw new ArgumentException();
 
            // add it to completed contexts collection
            bool needsCompensation = childContext.Activity.NeedsCompensation;
            if (needsCompensation || forcePersist)
            {
                // add it to completed contexts
                List<ActivityExecutionContextInfo> completedContexts = this.ownerContext.Activity.ContextActivity.GetValue(Activity.CompletedExecutionContextsProperty) as List<ActivityExecutionContextInfo>;
                if (completedContexts == null)
                {
                    completedContexts = new List<ActivityExecutionContextInfo>();
                    this.ownerContext.Activity.ContextActivity.SetValue(Activity.CompletedExecutionContextsProperty, completedContexts);
                }
 
                if (needsCompensation)
                    childContextInfo.Flags = PersistFlags.NeedsCompensation;
                if (forcePersist)
                    childContextInfo.Flags |= PersistFlags.ForcePersist;
 
                childContextInfo.SetCompletedOrderId(this.ownerContext.Activity.IncrementCompletedOrderId());
                completedContexts.Add(childContextInfo);
 
                // ask runtime to save the context activity
                this.ownerContext.Activity.WorkflowCoreRuntime.SaveContextActivity(childContext.Activity);
            }
 
            // remove it from active contexts
            activeContexts.Remove(childContext.Activity.ContextActivity);
            this.executionContexts.Remove(childContext);
 
            //Case for those context which has compensatable child context, when those context
            //are completed at the end of Compensation chain we need to uninitialize the context
            //activity associated to them.
            if (childContext.Activity.ContextActivity.CanUninitializeNow && childContext.Activity.ContextActivity.ExecutionResult != ActivityExecutionResult.Uninitialized)
            {
                childContext.Activity.ContextActivity.Uninitialize(this.ownerContext.Activity.RootActivity.WorkflowCoreRuntime);
                childContext.Activity.ContextActivity.SetValue(Activity.ExecutionResultProperty, ActivityExecutionResult.Uninitialized);
            }
 
            // unregister it from runtime
            this.ownerContext.Activity.WorkflowCoreRuntime.UnregisterContextActivity(childContext.Activity);
 
            if (!(needsCompensation || forcePersist))
            {
                childContext.Activity.Dispose();
            }
        }
 
        public ActivityExecutionContext GetExecutionContext(Activity activity)
        {
            if (this.ownerContext == null)
                throw new ObjectDisposedException("ActivityExecutionContextManager");
 
            if (activity == null)
                throw new ArgumentNullException("activity");
 
            ActivityExecutionContextInfo contextInfo = activity.GetValue(Activity.ActivityExecutionContextInfoProperty) as ActivityExecutionContextInfo;
 
            // Returns the first context for an activity with the same qualified name.
            foreach (ActivityExecutionContext context in ExecutionContexts)
            {
                if (contextInfo == null) //Template being passed.
                {
                    if (context.Activity.ContextActivity.QualifiedName == activity.QualifiedName)
                        return context;
                }
                else //Context Sensitive Activity
                {
                    if (context.ContextGuid.Equals(contextInfo.ContextGuid))
                        return context;
                }
            }
            return null;
        }
 
        public IEnumerable<Guid> PersistedExecutionContexts
        {
            get
            {
                if (this.ownerContext == null)
#pragma warning suppress 56503
                    throw new ObjectDisposedException("ActivityExecutionContextManager");
 
                List<ActivityExecutionContextInfo> completedContexts = this.ownerContext.Activity.ContextActivity.GetValue(Activity.CompletedExecutionContextsProperty) as List<ActivityExecutionContextInfo>;
                completedContexts = (completedContexts == null) ? new List<ActivityExecutionContextInfo>() : completedContexts;
 
                List<Guid> persistedContexts = new List<Guid>();
                foreach (ActivityExecutionContextInfo contextInfo in completedContexts)
                    if ((contextInfo.Flags & PersistFlags.ForcePersist) != 0)
                        persistedContexts.Add(contextInfo.ContextGuid);
 
                return persistedContexts;
            }
        }
 
        public ActivityExecutionContext GetPersistedExecutionContext(Guid contextGuid)
        {
            if (this.ownerContext == null)
                throw new ObjectDisposedException("ActivityExecutionContextManager");
 
            // Check if child execution context exists.
            IList<ActivityExecutionContextInfo> completedContexts = this.ownerContext.Activity.ContextActivity.GetValue(Activity.CompletedExecutionContextsProperty) as IList<ActivityExecutionContextInfo>;
            if (completedContexts == null)
                throw new ArgumentException();
 
            ActivityExecutionContextInfo contextInfo = null;
            foreach (ActivityExecutionContextInfo completedContextInfo in completedContexts)
            {
                if (completedContextInfo.ContextGuid == contextGuid && ((completedContextInfo.Flags & PersistFlags.ForcePersist) != 0))
                {
                    contextInfo = completedContextInfo;
                    break;
                }
            }
 
            if (contextInfo == null)
                throw new ArgumentException();
 
            // The caller would have to close the AEC with forcepersist the next time
            // around.
            contextInfo.Flags &= ~PersistFlags.ForcePersist;
            return DiscardPersistedExecutionContext(contextInfo);
        }
 
        #endregion
 
        internal void Dispose()
        {
            if (this.ownerContext != null)
            {
                foreach (ActivityExecutionContext executionContext in this.ExecutionContexts)
                    ((IDisposable)executionContext).Dispose();
                this.ownerContext = null;
            }
        }
 
        #region Internal members
 
        internal ReadOnlyCollection<ActivityExecutionContextInfo> CompletedExecutionContexts
        {
            get
            {
                List<ActivityExecutionContextInfo> completedContexts = this.ownerContext.Activity.ContextActivity.GetValue(Activity.CompletedExecutionContextsProperty) as List<ActivityExecutionContextInfo>;
                completedContexts = (completedContexts == null) ? new List<ActivityExecutionContextInfo>() : completedContexts;
                return completedContexts.AsReadOnly();
            }
        }
 
        internal ActivityExecutionContext DiscardPersistedExecutionContext(ActivityExecutionContextInfo contextInfo)
        {
            if (contextInfo == null)
                throw new ArgumentNullException("contextInfo");
 
            // check if child execution context
            IList<ActivityExecutionContextInfo> completedContexts = this.ownerContext.Activity.ContextActivity.GetValue(Activity.CompletedExecutionContextsProperty) as IList<ActivityExecutionContextInfo>;
            if (completedContexts == null || !completedContexts.Contains(contextInfo))
                throw new ArgumentException();
 
            // revoke from persistence service
            Activity revokedActivity = this.ownerContext.WorkflowCoreRuntime.LoadContextActivity(contextInfo, this.ownerContext.Activity.ContextActivity.GetActivityByName(contextInfo.ActivityQualifiedName));
            ((IDependencyObjectAccessor)revokedActivity).InitializeInstanceForRuntime(this.ownerContext.Activity.WorkflowCoreRuntime);
 
            // add it back to active contexts
            IList<Activity> activeContexts = (IList<Activity>)this.ownerContext.Activity.ContextActivity.GetValue(Activity.ActiveExecutionContextsProperty);
            if (activeContexts == null)
            {
                activeContexts = new List<Activity>();
                this.ownerContext.Activity.ContextActivity.SetValue(Activity.ActiveExecutionContextsProperty, activeContexts);
            }
            activeContexts.Add(revokedActivity);
 
            // inform workflow runtime
            this.ownerContext.Activity.WorkflowCoreRuntime.RegisterContextActivity(revokedActivity);
 
            // return the new context
            ActivityExecutionContext revokedContext = new ActivityExecutionContext(revokedActivity);
            this.executionContexts.Add(revokedContext);
            System.Workflow.Runtime.WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 0, "Revoking context {0}:{1}", revokedContext.ContextId, revokedContext.Activity.ContextActivity.QualifiedName);
 
            // remove it from completed contexts
            completedContexts.Remove(contextInfo);
            return revokedContext;
        }
 
        #endregion
    }
 
    #region Class ActivityExecutionContextInfo
 
    [Serializable]
    [Flags]
    internal enum PersistFlags : byte
    {
        NeedsCompensation = 1,
        ForcePersist = 2
    }
 
    [Serializable]
    internal sealed class ActivityExecutionContextInfo
    {
        private string qualifiedID = string.Empty;
        private int contextId = -1;
        private Guid contextGuid = Guid.Empty; //
        private int parentContextId = -1;
        private int completedOrderId = -1;
        private PersistFlags flags = 0;
 
        internal ActivityExecutionContextInfo(string qualifiedName, int contextId, Guid contextGuid, int parentContextId)
        {
            this.qualifiedID = qualifiedName;
            this.contextId = contextId;
            this.contextGuid = contextGuid;
            this.parentContextId = parentContextId;
        }
 
        internal int ContextId
        {
            get
            {
                return this.contextId;
            }
        }
 
        public Guid ContextGuid
        {
            get
            {
                return this.contextGuid;
            }
        }
 
        public string ActivityQualifiedName
        {
            get
            {
                return this.qualifiedID;
            }
        }
 
        public int CompletedOrderId
        {
            get
            {
                return this.completedOrderId;
            }
        }
 
        internal int ParentContextId
        {
            get
            {
                return this.parentContextId;
            }
        }
 
        internal void SetCompletedOrderId(int completedOrderId)
        {
            this.completedOrderId = completedOrderId;
        }
 
        internal PersistFlags Flags
        {
            get
            {
                return this.flags;
            }
 
            set
            {
                this.flags = value;
            }
        }
 
        public override int GetHashCode()
        {
            return contextGuid.GetHashCode();
        }
 
        public override bool Equals(object obj)
        {
            ActivityExecutionContextInfo otherContextInfo = obj as ActivityExecutionContextInfo;
 
            if (otherContextInfo != null)
            {
                return this.ContextGuid.Equals(otherContextInfo.ContextGuid);
            }
            return false;
        }
    }
 
    #endregion
}