|
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.Activities.Runtime
{
using System;
using System.Activities.DynamicUpdate;
using System.Collections.ObjectModel;
using System.Runtime;
using System.Runtime.Serialization;
using System.Security;
// can't add FuncCompletionCallbackWrapper<T> since we don't know what to close the generic with
[KnownType(typeof(ActivityCompletionCallbackWrapper))]
[KnownType(typeof(DelegateCompletionCallbackWrapper))]
[DataContract]
abstract class CompletionCallbackWrapper : CallbackWrapper
{
static Type completionCallbackType = typeof(CompletionCallback);
static Type[] completionCallbackParameters = new Type[] { typeof(NativeActivityContext), typeof(ActivityInstance) };
bool checkForCancelation;
bool needsToGatherOutputs;
protected CompletionCallbackWrapper(Delegate callback, ActivityInstance owningInstance)
: base(callback, owningInstance)
{
}
protected bool NeedsToGatherOutputs
{
get
{
return this.needsToGatherOutputs;
}
set
{
this.needsToGatherOutputs = value;
}
}
[DataMember(EmitDefaultValue = false, Name = "checkForCancelation")]
internal bool SerializedCheckForCancelation
{
get { return this.checkForCancelation; }
set { this.checkForCancelation = value; }
}
[DataMember(EmitDefaultValue = false, Name = "needsToGatherOutputs")]
internal bool SerializedNeedsToGatherOutputs
{
get { return this.needsToGatherOutputs; }
set { this.needsToGatherOutputs = value; }
}
public void CheckForCancelation()
{
this.checkForCancelation = true;
}
protected virtual void GatherOutputs(ActivityInstance completedInstance)
{
// No-op in the base class
}
internal WorkItem CreateWorkItem(ActivityInstance completedInstance, ActivityExecutor executor)
{
// We use the property to guard against the virtual method call
// since we don't need it in the common case
if (this.NeedsToGatherOutputs)
{
this.GatherOutputs(completedInstance);
}
CompletionWorkItem workItem;
if (this.checkForCancelation)
{
workItem = new CompletionWithCancelationCheckWorkItem(this, completedInstance);
}
else
{
workItem = executor.CompletionWorkItemPool.Acquire();
workItem.Initialize(this, completedInstance);
}
if (completedInstance.InstanceMap != null)
{
completedInstance.InstanceMap.AddEntry(workItem);
}
return workItem;
}
[Fx.Tag.SecurityNote(Critical = "Because any implementation will be calling EnsureCallback",
Safe = "Safe because the method needs to be part of an Activity and we are casting to the callback type and it has a very specific signature. The author of the callback is buying into being invoked from PT.")]
[SecuritySafeCritical]
protected internal abstract void Invoke(NativeActivityContext context, ActivityInstance completedInstance);
[DataContract]
public class CompletionWorkItem : ActivityExecutionWorkItem, ActivityInstanceMap.IActivityReference
{
CompletionCallbackWrapper callbackWrapper;
ActivityInstance completedInstance;
// Called by the Pool.
public CompletionWorkItem()
{
this.IsPooled = true;
}
// Only used by non-pooled base classes.
protected CompletionWorkItem(CompletionCallbackWrapper callbackWrapper, ActivityInstance completedInstance)
: base(callbackWrapper.ActivityInstance)
{
this.callbackWrapper = callbackWrapper;
this.completedInstance = completedInstance;
}
protected ActivityInstance CompletedInstance
{
get
{
return this.completedInstance;
}
}
[DataMember(Name = "callbackWrapper")]
internal CompletionCallbackWrapper SerializedCallbackWrapper
{
get { return this.callbackWrapper; }
set { this.callbackWrapper = value; }
}
[DataMember(Name = "completedInstance")]
internal ActivityInstance SerializedCompletedInstance
{
get { return this.completedInstance; }
set { this.completedInstance = value; }
}
public void Initialize(CompletionCallbackWrapper callbackWrapper, ActivityInstance completedInstance)
{
base.Reinitialize(callbackWrapper.ActivityInstance);
this.callbackWrapper = callbackWrapper;
this.completedInstance = completedInstance;
}
protected override void ReleaseToPool(ActivityExecutor executor)
{
base.ClearForReuse();
this.callbackWrapper = null;
this.completedInstance = null;
executor.CompletionWorkItemPool.Release(this);
}
public override void TraceCompleted()
{
if (TD.CompleteCompletionWorkItemIsEnabled())
{
TD.CompleteCompletionWorkItem(this.ActivityInstance.Activity.GetType().ToString(), this.ActivityInstance.Activity.DisplayName, this.ActivityInstance.Id, this.completedInstance.Activity.GetType().ToString(), this.completedInstance.Activity.DisplayName, this.completedInstance.Id);
}
}
public override void TraceScheduled()
{
if (TD.ScheduleCompletionWorkItemIsEnabled())
{
TD.ScheduleCompletionWorkItem(this.ActivityInstance.Activity.GetType().ToString(), this.ActivityInstance.Activity.DisplayName, this.ActivityInstance.Id, this.completedInstance.Activity.GetType().ToString(), this.completedInstance.Activity.DisplayName, this.completedInstance.Id);
}
}
public override void TraceStarting()
{
if (TD.StartCompletionWorkItemIsEnabled())
{
TD.StartCompletionWorkItem(this.ActivityInstance.Activity.GetType().ToString(), this.ActivityInstance.Activity.DisplayName, this.ActivityInstance.Id, this.completedInstance.Activity.GetType().ToString(), this.completedInstance.Activity.DisplayName, this.completedInstance.Id);
}
}
public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager)
{
NativeActivityContext context = executor.NativeActivityContextPool.Acquire();
Fx.Assert(this.completedInstance.Activity != null, "Activity definition should always be associated with an activity instance.");
try
{
context.Initialize(this.ActivityInstance, executor, bookmarkManager);
this.callbackWrapper.Invoke(context, this.completedInstance);
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
this.ExceptionToPropagate = e;
}
finally
{
context.Dispose();
executor.NativeActivityContextPool.Release(context);
if (this.ActivityInstance.InstanceMap != null)
{
this.ActivityInstance.InstanceMap.RemoveEntry(this);
}
}
return true;
}
Activity ActivityInstanceMap.IActivityReference.Activity
{
get
{
return this.completedInstance.Activity;
}
}
void ActivityInstanceMap.IActivityReference.Load(Activity activity, ActivityInstanceMap instanceMap)
{
if (this.completedInstance.Activity == null)
{
((ActivityInstanceMap.IActivityReference)this.completedInstance).Load(activity, instanceMap);
}
}
}
[DataContract]
class CompletionWithCancelationCheckWorkItem : CompletionWorkItem
{
public CompletionWithCancelationCheckWorkItem(CompletionCallbackWrapper callbackWrapper, ActivityInstance completedInstance)
: base(callbackWrapper, completedInstance)
{
}
public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager)
{
if (this.CompletedInstance.State != ActivityInstanceState.Closed && this.ActivityInstance.IsPerformingDefaultCancelation)
{
this.ActivityInstance.MarkCanceled();
}
return base.Execute(executor, bookmarkManager);
}
}
}
}
|