1 namespace System.Workflow.Activities
2 {
3     #region Imports
4 
5     using System;
6     using System.Diagnostics;
7     using System.CodeDom;
8     using System.Drawing;
9     using System.Collections;
10     using System.ComponentModel;
11     using System.ComponentModel.Design;
12     using System.Workflow.ComponentModel;
13     using System.Workflow.ComponentModel.Design;
14     using System.Collections.Generic;
15     using System.Workflow.ComponentModel.Compiler;
16     using System.Workflow.Runtime;
17     using System.Workflow.Activities.Common;
18 
19     #endregion
20 
21     [ToolboxItem(false)]
22     [Designer(typeof(EventHandlersDesigner), typeof(IDesigner))]
23     [ToolboxBitmap(typeof(EventHandlersActivity), "Resources.events.png")]
24     [ActivityValidator(typeof(EventHandlersValidator))]
25     [SRCategory(SR.Standard)]
26     [AlternateFlowActivityAttribute]
27     [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
28     public sealed class EventHandlersActivity : CompositeActivity, IActivityEventListener<ActivityExecutionStatusChangedEventArgs>
29     {
EventHandlersActivity()30         public EventHandlersActivity()
31         {
32         }
33 
EventHandlersActivity(string name)34         public EventHandlersActivity(string name)
35             : base(name)
36         {
37         }
38 
39         #region Runtime State Specific Dependency Property
40         static DependencyProperty ActivityStateProperty = DependencyProperty.Register("ActivityState", typeof(List<EventHandlerEventActivitySubscriber>), typeof(EventHandlersActivity));
41         static DependencyProperty IsScopeCompletedProperty = DependencyProperty.Register("IsScopeCompleted", typeof(bool), typeof(EventHandlersActivity), new PropertyMetadata(false));
42 
43         private List<EventHandlerEventActivitySubscriber> ActivityState
44         {
45             get
46             {
47                 return (List<EventHandlerEventActivitySubscriber>)base.GetValue(ActivityStateProperty);
48             }
49             set
50             {
51                 if (value == null)
52                     base.RemoveProperty(ActivityStateProperty);
53                 else
54                     base.SetValue(ActivityStateProperty, value);
55             }
56         }
57 
58         private bool IsScopeCompleted
59         {
60             get
61             {
62                 return (bool)base.GetValue(IsScopeCompletedProperty);
63             }
64             set
65             {
66                 base.SetValue(IsScopeCompletedProperty, value);
67             }
68         }
69         #endregion
70 
UnsubscribeAndClose()71         internal void UnsubscribeAndClose()
72         {
73             base.Invoke<EventArgs>(this.OnUnsubscribeAndClose, EventArgs.Empty);
74         }
75 
76         #region Protected Methods
OnClosed(IServiceProvider provider)77         protected override void OnClosed(IServiceProvider provider)
78         {
79             base.RemoveProperty(EventHandlersActivity.ActivityStateProperty);
80             base.RemoveProperty(EventHandlersActivity.IsScopeCompletedProperty);
81         }
82 
Initialize(IServiceProvider provider)83         protected override void Initialize(IServiceProvider provider)
84         {
85             if (this.Parent == null)
86                 throw new InvalidOperationException(SR.GetString(SR.Error_MustHaveParent));
87 
88             base.Initialize(provider);
89         }
90 
Execute(ActivityExecutionContext executionContext)91         protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
92         {
93             if (executionContext == null)
94                 throw new ArgumentNullException("executionContext");
95 
96             List<EventHandlerEventActivitySubscriber> eventActivitySubscribers = new List<EventHandlerEventActivitySubscriber>();
97             this.ActivityState = eventActivitySubscribers;
98 
99             for (int i = 0; i < this.EnabledActivities.Count; ++i)
100             {
101                 EventDrivenActivity childActivity = this.EnabledActivities[i] as EventDrivenActivity;
102                 EventHandlerEventActivitySubscriber eventDrivenSubscriber = new EventHandlerEventActivitySubscriber(childActivity);
103                 eventActivitySubscribers.Add(eventDrivenSubscriber);
104                 childActivity.EventActivity.Subscribe(executionContext, eventDrivenSubscriber);
105             }
106             return ActivityExecutionStatus.Executing;
107         }
Cancel(ActivityExecutionContext executionContext)108         protected override ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext)
109         {
110             if (executionContext == null)
111                 throw new ArgumentNullException("executionContext");
112 
113             if (this.ActivityState == null)
114                 return ActivityExecutionStatus.Closed;
115 
116             bool scopeCompleted = this.IsScopeCompleted;
117             bool canCloseNow = true;
118 
119             for (int i = 0; i < this.EnabledActivities.Count; ++i)
120             {
121                 EventDrivenActivity childActivity = this.EnabledActivities[i] as EventDrivenActivity;
122                 EventHandlerEventActivitySubscriber eventActivitySubscriber = this.ActivityState[i] as EventHandlerEventActivitySubscriber;
123 
124                 eventActivitySubscriber.PendingExecutionCount = 0;
125 
126                 ActivityExecutionContextManager contextManager = executionContext.ExecutionContextManager;
127                 ActivityExecutionContext childContext = contextManager.GetExecutionContext(childActivity);
128 
129                 if (childContext != null)
130                 {
131                     switch (childContext.Activity.ExecutionStatus)
132                     {
133                         case ActivityExecutionStatus.Canceling:
134                         case ActivityExecutionStatus.Faulting:
135                             canCloseNow = false;
136                             break;
137                         case ActivityExecutionStatus.Executing:
138                             childContext.CancelActivity(childContext.Activity);
139                             canCloseNow = false;
140                             break;
141                     }
142                 }
143 
144                 if (!scopeCompleted) //UnSubscribe from event.
145                 {
146                     childActivity.EventActivity.Unsubscribe(executionContext, eventActivitySubscriber);
147                 }
148             }
149 
150             if (canCloseNow)
151             {
152                 this.ActivityState = null;
153                 return ActivityExecutionStatus.Closed;
154             }
155             else
156             {
157                 return this.ExecutionStatus;
158             }
159         }
OnActivityChangeAdd(ActivityExecutionContext executionContext, Activity addedActivity)160         protected override void OnActivityChangeAdd(ActivityExecutionContext executionContext, Activity addedActivity)
161         {
162             if (executionContext == null)
163                 throw new ArgumentNullException("executionContext");
164 
165             if (addedActivity == null)
166                 throw new ArgumentNullException("addedActivity");
167 
168             EventDrivenActivity eda = addedActivity as EventDrivenActivity;
169 
170             EventHandlersActivity activity = (EventHandlersActivity)executionContext.Activity as EventHandlersActivity;
171             EventHandlerEventActivitySubscriber eventActivitySubscriber = new EventHandlerEventActivitySubscriber(eda);
172 
173             if (activity.ExecutionStatus == ActivityExecutionStatus.Executing && activity.ActivityState != null && !activity.IsScopeCompleted)
174             {
175                 eda.EventActivity.Subscribe(executionContext, eventActivitySubscriber);
176                 activity.ActivityState.Insert(activity.EnabledActivities.IndexOf(addedActivity), eventActivitySubscriber);
177             }
178         }
OnActivityChangeRemove(ActivityExecutionContext executionContext, Activity removedActivity)179         protected override void OnActivityChangeRemove(ActivityExecutionContext executionContext, Activity removedActivity)
180         {
181             if (executionContext == null)
182                 throw new ArgumentNullException("executionContext");
183             if (removedActivity == null)
184                 throw new ArgumentNullException("removedActivity");
185 
186             EventDrivenActivity eda = removedActivity as EventDrivenActivity;
187 
188             // find out the status of the scope
189             EventHandlersActivity activity = (EventHandlersActivity)executionContext.Activity as EventHandlersActivity;
190 
191             if (activity.ExecutionStatus == ActivityExecutionStatus.Executing && activity.ActivityState != null && !activity.IsScopeCompleted)
192             {
193                 for (int i = 0; i < activity.ActivityState.Count; ++i)
194                 {
195                     EventHandlerEventActivitySubscriber eventSubscriber = activity.ActivityState[i];
196                     if (eventSubscriber.eventDrivenActivity.QualifiedName.Equals(removedActivity.QualifiedName))
197                     {
198                         eda.EventActivity.Unsubscribe(executionContext, eventSubscriber);
199                         activity.ActivityState.RemoveAt(i);
200                         return;
201                     }
202                 }
203             }
204         }
205 
OnWorkflowChangesCompleted(ActivityExecutionContext executionContext)206         protected override void OnWorkflowChangesCompleted(ActivityExecutionContext executionContext)
207         {
208             if (executionContext == null)
209                 throw new ArgumentNullException("executionContext");
210 
211             base.OnWorkflowChangesCompleted(executionContext);
212 
213             if (this.ActivityState != null)
214             {
215                 switch (this.ExecutionStatus)
216                 {
217                     case ActivityExecutionStatus.Executing:
218                         if (this.IsScopeCompleted && AllHandlersAreQuiet(this, executionContext))
219                             executionContext.CloseActivity();
220                         break;
221                     case ActivityExecutionStatus.Faulting:
222                     case ActivityExecutionStatus.Canceling:
223                         if (AllHandlersAreQuiet(this, executionContext))
224                             executionContext.CloseActivity();
225                         break;
226                     default:
227                         break;
228                 }
229             }
230         }
231         #endregion
232 
233         #region Private Impls
234 
235         #region IActivityEventListener<ActivityExecutionStatusChangedEventArgs> Members
236 
OnEvent(object sender, ActivityExecutionStatusChangedEventArgs e)237         void IActivityEventListener<ActivityExecutionStatusChangedEventArgs>.OnEvent(object sender, ActivityExecutionStatusChangedEventArgs e)
238         {
239             if (sender == null)
240                 throw new ArgumentNullException("sender");
241             if (e == null)
242                 throw new ArgumentNullException("e");
243 
244             ActivityExecutionContext context = sender as ActivityExecutionContext;
245             if (context == null)
246                 throw new ArgumentException(SR.Error_SenderMustBeActivityExecutionContext, "sender");
247 
248             EventDrivenActivity eda = e.Activity as EventDrivenActivity;
249             EventHandlersActivity eventHandlers = context.Activity as EventHandlersActivity;
250 
251             e.Activity.UnregisterForStatusChange(Activity.ClosedEvent, this);
252 
253             ActivityExecutionContextManager contextManager = context.ExecutionContextManager;
254             contextManager.CompleteExecutionContext(contextManager.GetExecutionContext(eda));
255 
256             switch (eventHandlers.ExecutionStatus)
257             {
258                 case ActivityExecutionStatus.Executing:
259                     for (int i = 0; i < eventHandlers.EnabledActivities.Count; ++i)
260                     {
261                         if (eventHandlers.EnabledActivities[i].QualifiedName.Equals(eda.QualifiedName))
262                         {
263                             EventHandlerEventActivitySubscriber eventActivitySubscriber = eventHandlers.ActivityState[i];
264 
265                             if (eventActivitySubscriber.PendingExecutionCount > 0)
266                             {
267                                 eventActivitySubscriber.PendingExecutionCount--;
268                                 eventActivitySubscriber.IsBlocked = false;
269 
270                                 ActivityExecutionContext childContext = contextManager.CreateExecutionContext(eventHandlers.EnabledActivities[i]);
271                                 childContext.Activity.RegisterForStatusChange(Activity.ClosedEvent, this);
272                                 childContext.ExecuteActivity(childContext.Activity);
273                             }
274                             else
275                             {
276                                 eventActivitySubscriber.IsBlocked = true;
277                                 if (eventHandlers.IsScopeCompleted && AllHandlersAreQuiet(eventHandlers, context))
278                                     context.CloseActivity();
279                             }
280                             break;
281                         }
282                     }
283                     break;
284 
285                 case ActivityExecutionStatus.Canceling:
286                 case ActivityExecutionStatus.Faulting:
287                     if (AllHandlersAreQuiet(eventHandlers, context))
288                         context.CloseActivity();
289                     break;
290             }
291         }
292 
293         #endregion
294 
295         #region Helpers
AllHandlersAreQuiet(EventHandlersActivity handlers, ActivityExecutionContext context)296         private bool AllHandlersAreQuiet(EventHandlersActivity handlers, ActivityExecutionContext context)
297         {
298             ActivityExecutionContextManager contextManager = context.ExecutionContextManager;
299 
300             for (int i = 0; i < handlers.EnabledActivities.Count; ++i)
301             {
302                 EventDrivenActivity eventDriven = handlers.EnabledActivities[i] as EventDrivenActivity;
303                 if (contextManager.GetExecutionContext(eventDriven) != null || (handlers.ActivityState != null && handlers.ActivityState[i].PendingExecutionCount > 0))
304                     return false;
305             }
306             return true;
307         }
OnUnsubscribeAndClose(object sender, EventArgs args)308         private void OnUnsubscribeAndClose(object sender, EventArgs args)
309         {
310             if (sender == null)
311                 throw new ArgumentNullException("sender");
312             if (args == null)
313                 throw new ArgumentNullException("args");
314 
315             ActivityExecutionContext context = (ActivityExecutionContext)sender;
316             if (context == null)
317                 throw new ArgumentException("sender");
318 
319             EventHandlersActivity handlers = context.Activity as EventHandlersActivity;
320             if (context.Activity.ExecutionStatus != ActivityExecutionStatus.Executing)
321                 return;
322 
323             Debug.Assert(!handlers.IsScopeCompleted, "Only notified of scope body completion once");
324             handlers.IsScopeCompleted = true;
325 
326             ActivityExecutionContextManager contextManager = context.ExecutionContextManager;
327             bool readyToClose = true;
328             for (int i = 0; i < handlers.EnabledActivities.Count; ++i)
329             {
330                 EventDrivenActivity evtDriven = handlers.EnabledActivities[i] as EventDrivenActivity;
331                 EventHandlerEventActivitySubscriber eventSubscriber = handlers.ActivityState[i];
332                 evtDriven.EventActivity.Unsubscribe(context, eventSubscriber);
333 
334                 if (contextManager.GetExecutionContext(evtDriven) != null || handlers.ActivityState[i].PendingExecutionCount != 0)
335                     readyToClose = false;
336             }
337 
338             if (readyToClose)
339             {
340                 handlers.ActivityState = null;
341                 context.CloseActivity();
342             }
343         }
344         #endregion
345 
346         #region EventSubscriber
347         [Serializable]
348         private sealed class EventHandlerEventActivitySubscriber : IActivityEventListener<QueueEventArgs>
349         {
350             bool isBlocked;
351             int numOfMsgs;
352 
353             internal EventDrivenActivity eventDrivenActivity;
354 
EventHandlerEventActivitySubscriber(EventDrivenActivity eventDriven)355             internal EventHandlerEventActivitySubscriber(EventDrivenActivity eventDriven)
356             {
357                 isBlocked = true;
358                 numOfMsgs = 0;
359                 this.eventDrivenActivity = eventDriven;
360             }
361 
362             internal bool IsBlocked
363             {
364                 get
365                 {
366                     return isBlocked;
367                 }
368                 set
369                 {
370                     isBlocked = value;
371                 }
372             }
373 
374             internal int PendingExecutionCount
375             {
376                 get
377                 {
378                     return numOfMsgs;
379                 }
380                 set
381                 {
382                     numOfMsgs = value;
383                 }
384             }
385 
OnEvent(object sender, QueueEventArgs e)386             void IActivityEventListener<QueueEventArgs>.OnEvent(object sender, QueueEventArgs e)
387             {
388                 if (sender == null)
389                     throw new ArgumentNullException("sender");
390                 if (e == null)
391                     throw new ArgumentNullException("e");
392                 ActivityExecutionContext context = sender as ActivityExecutionContext;
393 
394                 if (context == null)
395                     throw new ArgumentException("sender");
396 
397                 EventHandlersActivity handlers = context.Activity as EventHandlersActivity;
398 
399                 if (handlers.ExecutionStatus != ActivityExecutionStatus.Executing)
400                     return;
401 
402                 if (!handlers.EnabledActivities.Contains(eventDrivenActivity))
403                     return; //Activity is dynamically removed.
404 
405                 if (IsBlocked)
406                 {
407                     IsBlocked = false;
408                     ActivityExecutionContextManager contextManager = context.ExecutionContextManager;
409                     ActivityExecutionContext childContext = contextManager.CreateExecutionContext(eventDrivenActivity);
410                     childContext.Activity.RegisterForStatusChange(Activity.ClosedEvent, handlers);
411                     childContext.ExecuteActivity(childContext.Activity);
412                 }
413                 else
414                 {
415                     PendingExecutionCount++;
416                 }
417             }
418         }
419         #endregion
420         #endregion
421 
422         [Browsable(false)]
423         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
GetDynamicActivity(Activity childActivity)424         private Activity GetDynamicActivity(Activity childActivity)
425         {
426             if (childActivity == null)
427                 throw new ArgumentNullException("childActivity");
428 
429             if (!this.EnabledActivities.Contains(childActivity))
430                 throw new ArgumentException(SR.GetString(SR.Error_EventHandlersChildNotFound), "childActivity");
431             else
432             {
433                 Activity[] dynamicChildActivity = this.GetDynamicActivities(childActivity);
434 
435                 if (dynamicChildActivity.Length != 0)
436                     return dynamicChildActivity[0];
437                 else
438                     return null;
439             }
440         }
441 
GetDynamicActivity(String childActivityName)442         public Activity GetDynamicActivity(String childActivityName)
443         {
444             if (childActivityName == null)
445                 throw new ArgumentNullException("childActivityName");
446 
447             Activity childActivity = null;
448 
449             for (int i = 0; i < this.EnabledActivities.Count; ++i)
450             {
451                 if (this.EnabledActivities[i].QualifiedName.Equals(childActivityName))
452                 {
453                     childActivity = this.EnabledActivities[i];
454                     break;
455                 }
456             }
457 
458             if (childActivity != null)
459                 return GetDynamicActivity(childActivity);
460 
461             throw new ArgumentException(SR.GetString(SR.Error_EventHandlersChildNotFound), "childActivityName");
462         }
463     }
464 
465     internal sealed class EventHandlersValidator : CompositeActivityValidator
466     {
Validate(ValidationManager manager, object obj)467         public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
468         {
469             ValidationErrorCollection validationErrors = base.Validate(manager, obj);
470 
471             EventHandlersActivity eventHandlers = obj as EventHandlersActivity;
472             if (eventHandlers == null)
473                 throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(EventHandlersActivity).FullName), "obj");
474 
475             if (eventHandlers.Parent == null)
476             {
477                 validationErrors.Add(new ValidationError(SR.GetString(SR.Error_MustHaveParent), ErrorNumbers.Error_EventHandlersDeclParentNotScope));
478                 return validationErrors;
479             }
480 
481             // Parent must support event handlers
482             if (!(eventHandlers.Parent is EventHandlingScopeActivity))
483                 validationErrors.Add(new ValidationError(SR.GetString(SR.Error_EventHandlersDeclParentNotScope, eventHandlers.Parent.QualifiedName), ErrorNumbers.Error_EventHandlersDeclParentNotScope));
484 
485             bool bNotAllEventHandler = false;
486             foreach (Activity activity in eventHandlers.EnabledActivities)
487             {
488                 if (!(activity is EventDrivenActivity))
489                     bNotAllEventHandler = true;
490             }
491 
492             // validate that all child activities are event driven activities.
493             if (bNotAllEventHandler)
494                 validationErrors.Add(new ValidationError(SR.GetString(SR.Error_ListenNotAllEventDriven), ErrorNumbers.Error_ListenNotAllEventDriven));
495 
496             return validationErrors;
497         }
498     }
499 }
500