191 lines
7.1 KiB
C#
191 lines
7.1 KiB
C#
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Text;
|
||
|
using System.Workflow.Runtime.Hosting;
|
||
|
using System.Workflow.ComponentModel;
|
||
|
using System.Diagnostics;
|
||
|
using System.Diagnostics.CodeAnalysis;
|
||
|
using System.Collections;
|
||
|
|
||
|
namespace System.Workflow.Runtime
|
||
|
{
|
||
|
[Serializable]
|
||
|
[Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")]
|
||
|
public class TimerEventSubscriptionCollection : ICollection
|
||
|
{
|
||
|
[SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes",
|
||
|
Justification = "Design has been approved. This is a false positive. DependencyProperty is an immutable type.")]
|
||
|
public readonly static DependencyProperty TimerCollectionProperty = DependencyProperty.RegisterAttached("TimerCollection", typeof(TimerEventSubscriptionCollection), typeof(TimerEventSubscriptionCollection));
|
||
|
|
||
|
private object locker = new Object();
|
||
|
private KeyedPriorityQueue<Guid, TimerEventSubscription, DateTime> queue = new KeyedPriorityQueue<Guid, TimerEventSubscription, DateTime>();
|
||
|
#pragma warning disable 0414
|
||
|
private bool suspended = false; // no longer used but required for binary compatibility of serialization format
|
||
|
#pragma warning restore 0414
|
||
|
[NonSerialized]
|
||
|
private IWorkflowCoreRuntime executor;
|
||
|
private Guid instanceId;
|
||
|
|
||
|
internal TimerEventSubscriptionCollection(IWorkflowCoreRuntime executor, Guid instanceId)
|
||
|
{
|
||
|
this.executor = executor;
|
||
|
this.instanceId = instanceId;
|
||
|
WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "TimerEventSubscriptionQueue: {0} Created", instanceId);
|
||
|
this.queue.FirstElementChanged += OnFirstElementChanged;
|
||
|
}
|
||
|
|
||
|
internal void Enqueue(TimerEventSubscription timerEventSubscription)
|
||
|
{
|
||
|
lock (locker)
|
||
|
{
|
||
|
WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "TimerEventSubscriptionQueue: {0} Enqueue Timer {1} for {2} ", instanceId, timerEventSubscription.SubscriptionId, timerEventSubscription.ExpiresAt);
|
||
|
queue.Enqueue(timerEventSubscription.SubscriptionId, timerEventSubscription, timerEventSubscription.ExpiresAt);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal IWorkflowCoreRuntime Executor
|
||
|
{
|
||
|
get { return executor; }
|
||
|
set { executor = value; }
|
||
|
}
|
||
|
|
||
|
public TimerEventSubscription Peek()
|
||
|
{
|
||
|
lock (locker)
|
||
|
{
|
||
|
return queue.Peek();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal TimerEventSubscription Dequeue()
|
||
|
{
|
||
|
lock (locker)
|
||
|
{
|
||
|
TimerEventSubscription retval = queue.Dequeue();
|
||
|
if (retval != null)
|
||
|
WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "TimerEventSubscriptionQueue: {0} Dequeue Timer {1} for {2} ", instanceId, retval.SubscriptionId, retval.ExpiresAt);
|
||
|
return retval;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Remove(Guid timerSubscriptionId)
|
||
|
{
|
||
|
lock (locker)
|
||
|
{
|
||
|
WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "TimerEventSubscriptionQueue: {0} Remove Timer {1}", instanceId, timerSubscriptionId);
|
||
|
queue.Remove(timerSubscriptionId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void OnFirstElementChanged(object source, KeyedPriorityQueueHeadChangedEventArgs<TimerEventSubscription> e)
|
||
|
{
|
||
|
lock (locker)
|
||
|
{
|
||
|
ITimerService timerService = this.executor.GetService(typeof(ITimerService)) as ITimerService;
|
||
|
if (e.NewFirstElement != null && executor != null)
|
||
|
{
|
||
|
WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "TimerEventSubscriptionQueue: {0} Schedule Timer {1} for {2} ", instanceId, e.NewFirstElement.SubscriptionId, e.NewFirstElement.ExpiresAt);
|
||
|
timerService.ScheduleTimer(executor.ProcessTimersCallback, e.NewFirstElement.WorkflowInstanceId, e.NewFirstElement.ExpiresAt, e.NewFirstElement.SubscriptionId);
|
||
|
}
|
||
|
if (e.OldFirstElement != null)
|
||
|
{
|
||
|
WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "TimerEventSubscriptionQueue: {0} Unschedule Timer {1} for {2} ", instanceId, e.OldFirstElement.SubscriptionId, e.OldFirstElement.ExpiresAt);
|
||
|
timerService.CancelTimer(e.OldFirstElement.SubscriptionId);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void SuspendDelivery()
|
||
|
{
|
||
|
lock (locker)
|
||
|
{
|
||
|
WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "TimerEventSubscriptionQueue: {0} Suspend", instanceId);
|
||
|
WorkflowSchedulerService schedulerService = this.executor.GetService(typeof(WorkflowSchedulerService)) as WorkflowSchedulerService;
|
||
|
TimerEventSubscription sub = queue.Peek();
|
||
|
if (sub != null)
|
||
|
{
|
||
|
schedulerService.Cancel(sub.SubscriptionId);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void ResumeDelivery()
|
||
|
{
|
||
|
lock (locker)
|
||
|
{
|
||
|
WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "TimerEventSubscriptionQueue: {0} Resume", instanceId);
|
||
|
WorkflowSchedulerService schedulerService = this.executor.GetService(typeof(WorkflowSchedulerService)) as WorkflowSchedulerService;
|
||
|
TimerEventSubscription sub = queue.Peek();
|
||
|
if (sub != null)
|
||
|
{
|
||
|
schedulerService.Schedule(executor.ProcessTimersCallback, sub.WorkflowInstanceId, sub.ExpiresAt, sub.SubscriptionId);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Add(TimerEventSubscription item)
|
||
|
{
|
||
|
if (item == null)
|
||
|
throw new ArgumentNullException("item");
|
||
|
this.Enqueue(item);
|
||
|
}
|
||
|
|
||
|
|
||
|
public void Remove(TimerEventSubscription item)
|
||
|
{
|
||
|
if (item == null)
|
||
|
throw new ArgumentNullException("item");
|
||
|
this.Remove(item.SubscriptionId);
|
||
|
}
|
||
|
|
||
|
#region ICollection Members
|
||
|
|
||
|
public void CopyTo(Array array, int index)
|
||
|
{
|
||
|
TimerEventSubscription[] tes = null;
|
||
|
lock (locker)
|
||
|
{
|
||
|
tes = new TimerEventSubscription[queue.Count];
|
||
|
queue.Values.CopyTo(tes, 0);
|
||
|
}
|
||
|
if (tes != null)
|
||
|
tes.CopyTo(array, index);
|
||
|
}
|
||
|
|
||
|
public int Count
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return queue.Count;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool IsSynchronized
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public object SyncRoot
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return locker;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region IEnumerable Members
|
||
|
|
||
|
public IEnumerator GetEnumerator()
|
||
|
{
|
||
|
return queue.Values.GetEnumerator();
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
}
|
||
|
}
|