File: AuthoringOM\Behaviors\ExceptionHandlers.cs
Project: ndp\cdf\src\WF\Common\System.Workflow.ComponentModel.csproj (System.Workflow.ComponentModel)
namespace System.Workflow.ComponentModel
{
    #region Imports
 
    using System;
    using System.Diagnostics;
    using System.Reflection;
    using System.Drawing;
    using System.Collections;
    using System.CodeDom;
    using System.Globalization;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Workflow.ComponentModel;
    using System.Workflow.ComponentModel.Design;
    using System.Workflow.ComponentModel.Compiler;
    using System.Collections.Generic;
 
    #endregion
 
    [ToolboxItem(false)]
    [Designer(typeof(FaultHandlersActivityDesigner), typeof(IDesigner))]
    [ToolboxBitmap(typeof(FaultHandlersActivity), "Resources.Exceptions.png")]
    [ActivityValidator(typeof(FaultHandlersActivityValidator))]
    [AlternateFlowActivity]
    [SRCategory(SR.Standard)]
    [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
    public sealed class FaultHandlersActivity : CompositeActivity, IActivityEventListener<ActivityExecutionStatusChangedEventArgs>
    {
        public FaultHandlersActivity()
        {
        }
 
        public FaultHandlersActivity(string name)
            : base(name)
        {
        }
 
        protected internal override void Initialize(IServiceProvider provider)
        {
            if (this.Parent == null)
                throw new InvalidOperationException(SR.GetString(SR.Error_MustHaveParent));
 
            base.Initialize(provider);
        }
 
        protected internal override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            if (executionContext == null)
                throw new ArgumentNullException("executionContext");
 
            Debug.Assert(this.Parent.GetValue(ActivityExecutionContext.CurrentExceptionProperty) != null, "No Exception contained by parent");
 
            Exception excep = this.Parent.GetValue(ActivityExecutionContext.CurrentExceptionProperty) as Exception;
 
            if (excep != null)
            {
                Type exceptionType = excep.GetType();
 
                foreach (FaultHandlerActivity exceptionHandler in this.EnabledActivities)
                {
                    if (CanHandleException(exceptionHandler, exceptionType))
                    {
                        // remove exception from here, I ate it
                        this.Parent.RemoveProperty(ActivityExecutionContext.CurrentExceptionProperty);
                        exceptionHandler.SetException(excep);
                        exceptionHandler.RegisterForStatusChange(Activity.ClosedEvent, this);
                        executionContext.ExecuteActivity(exceptionHandler);
                        return ActivityExecutionStatus.Executing;
                    }
                }
            }
            return ActivityExecutionStatus.Closed;
        }
 
        protected internal override ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext)
        {
            if (executionContext == null)
                throw new ArgumentNullException("executionContext");
 
            for (int i = 0; i < this.EnabledActivities.Count; ++i)
            {
                Activity childActivity = this.EnabledActivities[i];
 
                if (childActivity.ExecutionStatus == ActivityExecutionStatus.Executing)
                    executionContext.CancelActivity(childActivity);
                if (childActivity.ExecutionStatus == ActivityExecutionStatus.Canceling ||
                    childActivity.ExecutionStatus == ActivityExecutionStatus.Faulting)
                    return this.ExecutionStatus;
            }
            return ActivityExecutionStatus.Closed;
        }
 
        #region IActivityEventListener<ActivityExecutionStatusChangedEventArgs> Members
 
        void IActivityEventListener<ActivityExecutionStatusChangedEventArgs>.OnEvent(object sender, ActivityExecutionStatusChangedEventArgs e)
        {
            if (sender == null)
                throw new ArgumentNullException("sender");
            if (e == null)
                throw new ArgumentNullException("e");
 
            ActivityExecutionContext context = sender as ActivityExecutionContext;
            if (context == null)
                throw new ArgumentException(SR.Error_SenderMustBeActivityExecutionContext, "sender");
 
            e.Activity.UnregisterForStatusChange(Activity.ClosedEvent, this);
            context.CloseActivity();
        }
 
        [NonSerialized]
        bool activeChildRemoved = false;
 
        protected internal override void OnActivityChangeRemove(ActivityExecutionContext executionContext, Activity removedActivity)
        {
            if (removedActivity == null)
                throw new ArgumentNullException("removedActivity");
 
            if (executionContext == null)
                throw new ArgumentNullException("executionContext");
 
            if (removedActivity.ExecutionStatus == ActivityExecutionStatus.Closed && this.ExecutionStatus != ActivityExecutionStatus.Closed)
                activeChildRemoved = true;
 
            base.OnActivityChangeRemove(executionContext, removedActivity);
        }
 
        protected internal override void OnWorkflowChangesCompleted(ActivityExecutionContext executionContext)
        {
            if (executionContext == null)
                throw new ArgumentNullException("executionContext");
 
            if (activeChildRemoved)
            {
                executionContext.CloseActivity();
                activeChildRemoved = false;
            }
            base.OnWorkflowChangesCompleted(executionContext);
        }
        protected override void OnClosed(IServiceProvider provider)
        {
        }
        #endregion
 
        private bool CanHandleException(FaultHandlerActivity exceptionHandler, Type et)
        {
            Type canHandleType = exceptionHandler.FaultType;
            return (et == canHandleType || et.IsSubclassOf(canHandleType));
        }
    }
 
    internal sealed class FaultHandlersActivityValidator : CompositeActivityValidator
    {
        public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
        {
            ValidationErrorCollection validationErrors = base.Validate(manager, obj);
 
            FaultHandlersActivity exceptionHandlers = obj as FaultHandlersActivity;
            if (exceptionHandlers == null)
                throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(FaultHandlersActivity).FullName), "obj");
 
            Hashtable exceptionTypes = new Hashtable();
            ArrayList previousExceptionTypes = new ArrayList();
            bool bFoundNotFaultHandlerActivity = false;
            foreach (Activity activity in exceptionHandlers.EnabledActivities)
            {
                // All child activities must be FaultHandlerActivity
                if (!(activity is FaultHandlerActivity))
                {
                    if (!bFoundNotFaultHandlerActivity)
                    {
                        validationErrors.Add(new ValidationError(SR.GetString(SR.Error_FaultHandlersActivityDeclNotAllFaultHandlerActivityDecl), ErrorNumbers.Error_FaultHandlersActivityDeclNotAllFaultHandlerActivityDecl));
                        bFoundNotFaultHandlerActivity = true;
                    }
                }
                else
                {
                    FaultHandlerActivity exceptionHandler = (FaultHandlerActivity)activity;
                    Type catchType = exceptionHandler.FaultType;
                    if (catchType != null)
                    {
                        if (exceptionTypes[catchType] == null)
                        {
                            exceptionTypes[catchType] = 1;
                            previousExceptionTypes.Add(catchType);
                        }
                        else if ((int)exceptionTypes[catchType] == 1)
                        {
                            /*if (catchType == typeof(System.Exception))
                                validationErrors.Add(new ValidationError(SR.GetString(SR.Error_ScopeDuplicateFaultHandlerActivityForAll, exceptionHandlers.EnclosingDataContextActivity.GetType().Name), ErrorNumbers.Error_ScopeDuplicateFaultHandlerActivityForAll));
                            else*/
                            validationErrors.Add(new ValidationError(string.Format(CultureInfo.CurrentCulture, SR.GetString(SR.Error_ScopeDuplicateFaultHandlerActivityFor), new object[] { Helpers.GetEnclosingActivity(exceptionHandlers).GetType().Name, catchType.FullName }), ErrorNumbers.Error_ScopeDuplicateFaultHandlerActivityFor));
 
                            exceptionTypes[catchType] = 2;
                        }
 
                        foreach (Type previousType in previousExceptionTypes)
                        {
                            if (previousType != catchType && previousType.IsAssignableFrom(catchType))
                                validationErrors.Add(new ValidationError(SR.GetString(SR.Error_FaultHandlerActivityWrongOrder, catchType.Name, previousType.Name), ErrorNumbers.Error_FaultHandlerActivityWrongOrder));
                        }
                    }
                }
            }
 
            // fault handlers can not contain fault handlers, compensation handler and cancellation handler
            if (((ISupportAlternateFlow)exceptionHandlers).AlternateFlowActivities.Count > 0)
                validationErrors.Add(new ValidationError(SR.GetString(SR.Error_ModelingConstructsCanNotContainModelingConstructs), ErrorNumbers.Error_ModelingConstructsCanNotContainModelingConstructs));
 
            return validationErrors;
        }
    }
}