|
namespace System.Workflow.ComponentModel
{
using System;
using System.Drawing;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel.Design;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
[SRDescription(SR.CompensateActivityDescription)]
[ToolboxItem(typeof(ActivityToolboxItem))]
[Designer(typeof(CompensateDesigner), typeof(IDesigner))]
[ToolboxBitmap(typeof(CompensateActivity), "Resources.Compensate.png")]
[ActivityValidator(typeof(CompensateValidator))]
[SRCategory(SR.Standard)]
[Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")]
public sealed class CompensateActivity : Activity, IPropertyValueProvider, IActivityEventListener<ActivityExecutionStatusChangedEventArgs>
{
public CompensateActivity()
{
}
public CompensateActivity(string name)
: base(name)
{
}
public static readonly DependencyProperty TargetActivityNameProperty = DependencyProperty.Register("TargetActivityName", typeof(string), typeof(CompensateActivity), new PropertyMetadata("", DependencyPropertyOptions.Metadata));
[SRCategory(SR.Activity)]
[SRDescription(SR.CompensatableActivityDescr)]
[TypeConverter(typeof(PropertyValueProviderTypeConverter))]
[MergableProperty(false)]
[DefaultValue("")]
public string TargetActivityName
{
get
{
return base.GetValue(TargetActivityNameProperty) as string;
}
set
{
base.SetValue(TargetActivityNameProperty, value);
}
}
#region Protected Methods
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");
return CompensateTargetActivity(executionContext);
}
#endregion
#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");
if (e.ExecutionStatus == ActivityExecutionStatus.Closed)
{
// Remove status change subscription.
e.Activity.UnregisterForStatusChange(Activity.ClosedEvent, this);
// Do it again if there are any more.
ActivityExecutionStatus status = CompensateTargetActivity(context);
if (status == ActivityExecutionStatus.Closed)
context.CloseActivity();
}
}
#endregion
#region Execution Helpers
private ActivityExecutionStatus CompensateTargetActivity(ActivityExecutionContext context)
{
Activity targetActivity = null;
Activity commonParentActivity = context.Activity;
do
{
commonParentActivity = commonParentActivity.Parent;
targetActivity = commonParentActivity.GetActivityByName(this.TargetActivityName, true);
} while (targetActivity == null);
if (targetActivity is ICompensatableActivity &&
targetActivity.ExecutionStatus == ActivityExecutionStatus.Closed &&
targetActivity.ExecutionResult == ActivityExecutionResult.Succeeded)
{
// same execution context
targetActivity.RegisterForStatusChange(Activity.ClosedEvent, this);
context.CompensateActivity(targetActivity);
return context.Activity.ExecutionStatus;
}
else if (targetActivity.ExecutionStatus == ActivityExecutionStatus.Initialized)
{
// Template activity
// walk through active contexts
ActivityExecutionContextManager contextManager = context.ExecutionContextManager;
foreach (ActivityExecutionContext activeContext in contextManager.ExecutionContexts)
{
if (targetActivity.GetActivityByName(activeContext.Activity.QualifiedName, true) != null)
{
if (activeContext.Activity.ExecutionStatus == ActivityExecutionStatus.Compensating ||
activeContext.Activity.ExecutionStatus == ActivityExecutionStatus.Faulting ||
activeContext.Activity.ExecutionStatus == ActivityExecutionStatus.Canceling
)
return context.Activity.ExecutionStatus;
}
}
// walk through all completed execution contexts
for (int index = contextManager.CompletedExecutionContexts.Count - 1; index >= 0; index--)
{
//only compensate direct child during explicit compensation
ActivityExecutionContextInfo completedActivityInfo = contextManager.CompletedExecutionContexts[index];
if (((completedActivityInfo.Flags & PersistFlags.NeedsCompensation) != 0))
{
ActivityExecutionContext revokedExecutionContext = contextManager.DiscardPersistedExecutionContext(completedActivityInfo);
if (revokedExecutionContext.Activity is ICompensatableActivity)
{
revokedExecutionContext.Activity.RegisterForStatusChange(Activity.ClosedEvent, this);
revokedExecutionContext.CompensateActivity(revokedExecutionContext.Activity);
}
return context.Activity.ExecutionStatus;
}
}
}
else
{
// currently faulting, canceling, or compensating
if (CompensationUtils.TryCompensateLastCompletedChildActivity(context, targetActivity, this))
return context.Activity.ExecutionStatus;
}
return ActivityExecutionStatus.Closed;
}
#endregion
#region IPropertyValueProvider Members
ICollection IPropertyValueProvider.GetPropertyValues(ITypeDescriptorContext context)
{
if (context == null)
throw new ArgumentNullException("context");
return GetCompensatableTargets(this);
}
#endregion
#region Validation Helpers
internal static StringCollection GetCompensatableTargets(CompensateActivity compensate)
{
StringCollection targetList = new StringCollection();
CompositeActivity parent = compensate.Parent;
while (parent != null)
{
if ((parent is CompensationHandlerActivity) || (parent is FaultHandlersActivity) || (parent is CancellationHandlerActivity))
{
parent = parent.Parent;
if (parent != null)
{
if (Helpers.IsCustomActivity(parent))
targetList.Add(parent.UserData[UserDataKeys.CustomActivityDefaultName] as string);
else
targetList.Add(parent.Name);
foreach (Activity activity in parent.EnabledActivities)
{
if (activity is ICompensatableActivity)
targetList.Add(activity.Name);
}
}
break;
}
parent = parent.Parent;
}
return targetList;
}
#endregion
}
#region Validator
internal sealed class CompensateValidator : ActivityValidator
{
public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
{
ValidationErrorCollection validationErrors = base.Validate(manager, obj);
CompensateActivity compensate = obj as CompensateActivity;
if (compensate == null)
throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(CompensateActivity).FullName), "obj");
// Compensate must be in a CompensationHandler or FaultHandler
CompositeActivity parent = compensate.Parent;
while (parent != null)
{
if (parent is CompensationHandlerActivity || parent is FaultHandlerActivity || parent is CancellationHandlerActivity)
break;
parent = parent.Parent;
}
if (parent == null)
validationErrors.Add(new ValidationError(SR.GetString(SR.Error_CompensateBadNesting), ErrorNumbers.Error_CompensateBadNesting));
ValidationError error = null;
StringCollection targets = CompensateActivity.GetCompensatableTargets(compensate);
if (String.IsNullOrEmpty(compensate.TargetActivityName))
{
error = ValidationError.GetNotSetValidationError("TargetActivityName");
}
else if (!targets.Contains(compensate.TargetActivityName))
{
error = new ValidationError(SR.GetString(SR.Error_CompensateBadTargetTX, "TargetActivityName", compensate.TargetActivityName, compensate.QualifiedName), ErrorNumbers.Error_CompensateBadTargetTX, false, "TargetActivityName");
}
if (error != null)
validationErrors.Add(error);
return validationErrors;
}
}
#endregion
}
|