e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
361 lines
16 KiB
Plaintext
361 lines
16 KiB
Plaintext
namespace System.Workflow.ComponentModel
|
|
{
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Globalization;
|
|
|
|
[Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")]
|
|
public interface IActivityEventListener<T> where T : EventArgs
|
|
{
|
|
void OnEvent(object sender, T e);
|
|
}
|
|
|
|
[Serializable]
|
|
internal sealed class ActivityExecutorDelegateInfo<T> where T : EventArgs
|
|
{
|
|
private string activityQualifiedName = null;
|
|
private IActivityEventListener<T> eventListener = null;
|
|
private EventHandler<T> delegateValue = null;
|
|
private int contextId = -1;
|
|
private bool wantInTransact = false;
|
|
private string subscribedActivityQualifiedName = null;
|
|
|
|
public ActivityExecutorDelegateInfo(EventHandler<T> delegateValue, Activity contextActivity)
|
|
: this(false, delegateValue, contextActivity)
|
|
{
|
|
}
|
|
public ActivityExecutorDelegateInfo(IActivityEventListener<T> eventListener, Activity contextActivity)
|
|
: this(false, eventListener, contextActivity)
|
|
{
|
|
}
|
|
public ActivityExecutorDelegateInfo(EventHandler<T> delegateValue, Activity contextActivity, bool wantInTransact)
|
|
: this(delegateValue, contextActivity)
|
|
{
|
|
this.wantInTransact = wantInTransact;
|
|
}
|
|
public ActivityExecutorDelegateInfo(IActivityEventListener<T> eventListener, Activity contextActivity, bool wantInTransact)
|
|
: this(eventListener, contextActivity)
|
|
{
|
|
this.wantInTransact = wantInTransact;
|
|
}
|
|
internal ActivityExecutorDelegateInfo(bool useCurrentContext, EventHandler<T> delegateValue, Activity contextActivity)
|
|
{
|
|
this.delegateValue = delegateValue;
|
|
Activity target = delegateValue.Target as Activity;
|
|
|
|
if (contextActivity.WorkflowCoreRuntime != null)
|
|
{
|
|
if (useCurrentContext)
|
|
this.contextId = contextActivity.WorkflowCoreRuntime.CurrentActivity.ContextActivity.ContextId;
|
|
else
|
|
this.contextId = contextActivity.ContextId;
|
|
|
|
this.activityQualifiedName = (target ?? contextActivity.WorkflowCoreRuntime.CurrentActivity).QualifiedName;
|
|
}
|
|
else
|
|
{
|
|
this.contextId = 1;
|
|
this.activityQualifiedName = (target ?? contextActivity.RootActivity).QualifiedName;
|
|
}
|
|
}
|
|
internal ActivityExecutorDelegateInfo(bool useCurrentContext, IActivityEventListener<T> eventListener, Activity contextActivity)
|
|
{
|
|
this.eventListener = eventListener;
|
|
Activity target = eventListener as Activity;
|
|
if (contextActivity.WorkflowCoreRuntime != null)
|
|
{
|
|
if (useCurrentContext)
|
|
this.contextId = contextActivity.WorkflowCoreRuntime.CurrentActivity.ContextActivity.ContextId;
|
|
else
|
|
this.contextId = contextActivity.ContextId;
|
|
|
|
this.activityQualifiedName = (target ?? contextActivity.WorkflowCoreRuntime.CurrentActivity).QualifiedName;
|
|
}
|
|
else
|
|
{
|
|
this.contextId = 1;
|
|
this.activityQualifiedName = (target ?? contextActivity.RootActivity).QualifiedName;
|
|
}
|
|
}
|
|
public string ActivityQualifiedName
|
|
{
|
|
get
|
|
{
|
|
return this.activityQualifiedName;
|
|
}
|
|
}
|
|
public string SubscribedActivityQualifiedName
|
|
{
|
|
get
|
|
{
|
|
return this.subscribedActivityQualifiedName;
|
|
}
|
|
set
|
|
{
|
|
this.subscribedActivityQualifiedName = value;
|
|
}
|
|
|
|
}
|
|
public int ContextId
|
|
{
|
|
get
|
|
{
|
|
return this.contextId;
|
|
}
|
|
}
|
|
public EventHandler<T> HandlerDelegate
|
|
{
|
|
get
|
|
{
|
|
return this.delegateValue;
|
|
}
|
|
}
|
|
|
|
public IActivityEventListener<T> EventListener
|
|
{
|
|
get
|
|
{
|
|
return this.eventListener;
|
|
}
|
|
}
|
|
|
|
internal void InvokeDelegate(Activity currentContextActivity, T e, bool [....], bool transacted)
|
|
{
|
|
Activity targetContextActivity = currentContextActivity.WorkflowCoreRuntime.GetContextActivityForId(this.contextId);
|
|
if (targetContextActivity == null)
|
|
{
|
|
targetContextActivity = FindExecutorForActivityUp(currentContextActivity, this.activityQualifiedName);
|
|
if (targetContextActivity == null)
|
|
targetContextActivity = FindExecutorForActivityDown(currentContextActivity, this.activityQualifiedName);
|
|
}
|
|
if (targetContextActivity != null)
|
|
InvokeDelegate(currentContextActivity, targetContextActivity, e, [....], transacted);
|
|
}
|
|
public void InvokeDelegate(Activity currentContextActivity, T e, bool transacted)
|
|
{
|
|
// If in atomic and subscriber in same scope, or not in atomic scope at all
|
|
Activity targetContextActivity = FindExecutorForActivityUp(currentContextActivity, this.activityQualifiedName);
|
|
if (targetContextActivity == null)
|
|
targetContextActivity = FindExecutorForActivityDown(currentContextActivity, this.activityQualifiedName);
|
|
|
|
if (targetContextActivity != null)
|
|
InvokeDelegate(currentContextActivity, targetContextActivity, e, false, transacted);
|
|
}
|
|
private void InvokeDelegate(Activity currentContextActivity, Activity targetContextActivity, T e, bool [....], bool transacted)
|
|
{
|
|
ActivityExecutorDelegateOperation delegateOperation = null;
|
|
if (this.delegateValue != null)
|
|
delegateOperation = new ActivityExecutorDelegateOperation(this.activityQualifiedName, this.delegateValue, e, this.ContextId);
|
|
else
|
|
delegateOperation = new ActivityExecutorDelegateOperation(this.activityQualifiedName, this.eventListener, e, this.ContextId);
|
|
|
|
bool mayInvokeDelegateNow = MayInvokeDelegateNow(currentContextActivity);
|
|
if (mayInvokeDelegateNow && [....])
|
|
{
|
|
Activity targetActivity = targetContextActivity.GetActivityByName(this.activityQualifiedName);
|
|
using (currentContextActivity.WorkflowCoreRuntime.SetCurrentActivity(targetActivity))
|
|
{
|
|
delegateOperation.SynchronousInvoke = true;
|
|
delegateOperation.Run(currentContextActivity.WorkflowCoreRuntime);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If in atomic and subscriber not in same scope
|
|
// Queue it on the subscriber's baseExecutor
|
|
Activity targetActivity = targetContextActivity.GetActivityByName(this.activityQualifiedName);
|
|
currentContextActivity.WorkflowCoreRuntime.ScheduleItem(delegateOperation, ActivityExecutionContext.IsInAtomicTransaction(targetActivity), transacted, !mayInvokeDelegateNow);
|
|
}
|
|
}
|
|
private bool MayInvokeDelegateNow(Activity currentContextActivity)
|
|
{
|
|
// Ok to invoke right away if
|
|
// subscriber wants to participate in the current transaction
|
|
if ((this.activityQualifiedName == null) || (this.wantInTransact))
|
|
return true;
|
|
|
|
// If not in atomic scope at all,
|
|
if (!ActivityExecutionContext.IsInAtomicTransaction(currentContextActivity.WorkflowCoreRuntime.CurrentActivity))
|
|
return true;
|
|
|
|
// Has not started executing yet, queue it up for now
|
|
// Not letting it leak out for recv case any more
|
|
Activity targetContextActivity = currentContextActivity.WorkflowCoreRuntime.GetContextActivityForId(this.contextId);
|
|
if (targetContextActivity == null)
|
|
return false;
|
|
|
|
// or in atomic and subscriber in same scope,
|
|
// or in an atomic scope that's not in executing state, e.g. need to fire Scope closed status
|
|
Activity targetActivity = targetContextActivity.GetActivityByName(this.activityQualifiedName, true);
|
|
|
|
if (targetActivity == null)
|
|
return false;
|
|
|
|
if (ActivityExecutionContext.IsInAtomicTransaction(targetActivity) &&
|
|
ActivityExecutionContext.IsInAtomicTransaction(currentContextActivity.WorkflowCoreRuntime.CurrentActivity))
|
|
return true;
|
|
|
|
// If the activity receiving the subscription is the scope itself
|
|
if (targetActivity.MetaEquals(currentContextActivity))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
private Activity FindExecutorForActivityUp(Activity contextActivity, string activityQualifiedName)
|
|
{
|
|
while (contextActivity != null)
|
|
{
|
|
Activity activityToFind = contextActivity.GetActivityByName(activityQualifiedName, true);
|
|
if (activityToFind != null && activityToFind.ExecutionStatus != ActivityExecutionStatus.Initialized)
|
|
return contextActivity;
|
|
contextActivity = contextActivity.ParentContextActivity;
|
|
}
|
|
return contextActivity;
|
|
}
|
|
private Activity FindExecutorForActivityDown(Activity contextActivity, string activityQualifiedName)
|
|
{
|
|
Queue<Activity> contextActivities = new Queue<Activity>();
|
|
contextActivities.Enqueue(contextActivity);
|
|
while (contextActivities.Count > 0)
|
|
{
|
|
Activity contextActivity2 = contextActivities.Dequeue();
|
|
Activity activityToFind = contextActivity2.GetActivityByName(activityQualifiedName, true);
|
|
if (activityToFind != null && activityToFind.ExecutionStatus != ActivityExecutionStatus.Initialized)
|
|
return contextActivity2;
|
|
|
|
IList<Activity> nestedContextActivities = (IList<Activity>)contextActivity2.GetValue(Activity.ActiveExecutionContextsProperty);
|
|
if (nestedContextActivities != null)
|
|
{
|
|
foreach (Activity nestedContextActivity in nestedContextActivities)
|
|
contextActivities.Enqueue(nestedContextActivity);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
public override bool Equals(object obj)
|
|
{
|
|
ActivityExecutorDelegateInfo<T> otherObject = obj as ActivityExecutorDelegateInfo<T>;
|
|
if (otherObject == null)
|
|
return false;
|
|
|
|
return (
|
|
(otherObject.delegateValue == null && this.delegateValue == null) ||
|
|
(otherObject.delegateValue != null && otherObject.delegateValue.Equals(this.delegateValue))
|
|
) &&
|
|
(
|
|
(otherObject.eventListener == null && this.eventListener == null) ||
|
|
(otherObject.eventListener != null && otherObject.eventListener.Equals(this.eventListener))
|
|
) &&
|
|
otherObject.activityQualifiedName == this.activityQualifiedName &&
|
|
otherObject.contextId == this.contextId &&
|
|
otherObject.wantInTransact == this.wantInTransact;
|
|
}
|
|
public override int GetHashCode()
|
|
{
|
|
return this.delegateValue != null ? this.delegateValue.GetHashCode() : this.eventListener.GetHashCode() ^
|
|
this.activityQualifiedName.GetHashCode();
|
|
}
|
|
|
|
[Serializable]
|
|
private sealed class ActivityExecutorDelegateOperation : SchedulableItem
|
|
{
|
|
private string activityQualifiedName = null;
|
|
private IActivityEventListener<T> eventListener = null;
|
|
private EventHandler<T> delegateValue = null;
|
|
private T args = null;
|
|
|
|
[NonSerialized]
|
|
private bool synchronousInvoke = false;
|
|
|
|
public ActivityExecutorDelegateOperation(string activityQualifiedName, EventHandler<T> delegateValue, T e, int contextId)
|
|
: base(contextId, activityQualifiedName)
|
|
{
|
|
this.activityQualifiedName = activityQualifiedName;
|
|
this.delegateValue = delegateValue;
|
|
this.args = e;
|
|
}
|
|
public ActivityExecutorDelegateOperation(string activityQualifiedName, IActivityEventListener<T> eventListener, T e, int contextId)
|
|
: base(contextId, activityQualifiedName)
|
|
{
|
|
this.activityQualifiedName = activityQualifiedName;
|
|
this.eventListener = eventListener;
|
|
this.args = e;
|
|
}
|
|
internal bool SynchronousInvoke
|
|
{
|
|
get
|
|
{
|
|
return this.synchronousInvoke;
|
|
}
|
|
set
|
|
{
|
|
this.synchronousInvoke = value;
|
|
}
|
|
}
|
|
public override bool Run(IWorkflowCoreRuntime workflowCoreRuntime)
|
|
{
|
|
// get context activity
|
|
Activity contextActivity = workflowCoreRuntime.GetContextActivityForId(this.ContextId);
|
|
|
|
// Work around for ActivityExecutionStatusChangedEventArgs
|
|
ActivityExecutionStatusChangedEventArgs activityStatusChangeEventArgs = this.args as ActivityExecutionStatusChangedEventArgs;
|
|
if (activityStatusChangeEventArgs != null)
|
|
{
|
|
activityStatusChangeEventArgs.BaseExecutor = workflowCoreRuntime;
|
|
if (activityStatusChangeEventArgs.Activity == null)
|
|
{
|
|
// status change for an activity that has been deleted dynamically since.
|
|
activityStatusChangeEventArgs.BaseExecutor = null;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// get activity, if null, or if activity has already closed or just initialized, or if primary has closed and
|
|
// the target of the notification is not ActivityExecutionFilter, then
|
|
Activity activity = contextActivity.GetActivityByName(this.activityQualifiedName);
|
|
if (activity == null ||
|
|
((activity.ExecutionStatus == ActivityExecutionStatus.Closed || activity.ExecutionStatus == ActivityExecutionStatus.Initialized) && !this.synchronousInvoke) ||
|
|
(activity.HasPrimaryClosed && !(this.eventListener is ActivityExecutionFilter))
|
|
)
|
|
return false;
|
|
|
|
// call the delegate
|
|
try
|
|
{
|
|
using (workflowCoreRuntime.SetCurrentActivity(activity))
|
|
{
|
|
using (ActivityExecutionContext activityExecutionContext = new ActivityExecutionContext(activity))
|
|
{
|
|
if (this.delegateValue != null)
|
|
this.delegateValue(activityExecutionContext, this.args);
|
|
else
|
|
this.eventListener.OnEvent(activityExecutionContext, this.args);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
if (activity != null)
|
|
System.Workflow.Runtime.WorkflowTrace.Runtime.TraceEvent(TraceEventType.Error, 1, "Subscription handler of Activity {0} threw {1}", activity.QualifiedName, e.ToString());
|
|
else
|
|
System.Workflow.Runtime.WorkflowTrace.Runtime.TraceEvent(TraceEventType.Error, 1, "Subscription handler threw {0}", e.ToString());
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
// Work around for activity status change Event Args
|
|
if (activityStatusChangeEventArgs != null)
|
|
activityStatusChangeEventArgs.BaseExecutor = null;
|
|
}
|
|
return true;
|
|
}
|
|
public override string ToString()
|
|
{
|
|
return "SubscriptionEvent(" + "(" + this.ContextId.ToString(CultureInfo.CurrentCulture) + ")" + this.activityQualifiedName + ", " + this.args.ToString() + ")";
|
|
}
|
|
}
|
|
}
|
|
}
|