Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Workflow.ComponentModel / AuthoringOM / ScheduleChanges.cs
1 #pragma warning disable 1634, 1691
2 namespace System.Workflow.ComponentModel
3 {
4     #region Imports
5
6     using System;
7     using System.Collections;
8     using System.Collections.Specialized;
9     using System.Collections.Generic;
10     using System.Diagnostics;
11     using System.Globalization;
12     using System.ComponentModel;
13     using System.ComponentModel.Design;
14     using System.ComponentModel.Design.Serialization;
15     using System.Reflection;
16     using System.Workflow.ComponentModel.Compiler;
17     using System.Workflow.ComponentModel.Serialization;
18     using System.Workflow.ComponentModel.Design;
19     using System.Xml;
20     using System.IO;
21
22     #endregion
23
24     [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
25     public sealed class WorkflowChanges
26     {
27         #region Data members
28         public static readonly DependencyProperty ConditionProperty = DependencyProperty.RegisterAttached("Condition", typeof(ActivityCondition), typeof(WorkflowChanges), new PropertyMetadata(DependencyPropertyOptions.Metadata));
29         internal static DependencyProperty WorkflowChangeActionsProperty = DependencyProperty.RegisterAttached("WorkflowChangeActions", typeof(IList), typeof(WorkflowChanges), new PropertyMetadata(DependencyPropertyOptions.NonSerialized));
30         internal static DependencyProperty WorkflowChangeVersionProperty = DependencyProperty.RegisterAttached("WorkflowChangeVersion", typeof(Guid), typeof(WorkflowChanges), new PropertyMetadata(Guid.Empty, DependencyPropertyOptions.NonSerialized));
31
32         private Activity originalRootActivity = null;
33         private Activity clonedRootActivity = null;
34
35         private List<WorkflowChangeAction> modelChangeActions = new List<WorkflowChangeAction>();
36         private bool saved = false;
37
38         #endregion
39
40         #region Constuctor & Destructor
41
42         public WorkflowChanges(Activity rootActivity)
43         {
44             if (rootActivity == null)
45                 throw new ArgumentNullException("rootActivity");
46             if (!(rootActivity is CompositeActivity) || rootActivity.Parent != null)
47                 throw new ArgumentException(SR.GetString(SR.Error_RootActivityTypeInvalid2), "rootActivity");
48 #pragma warning suppress 56506
49             if (rootActivity.DesignMode)
50                 throw new InvalidOperationException(SR.GetString(SR.Error_NoRuntimeAvailable));
51
52             // get the original activity
53             this.originalRootActivity = (Activity)((Activity)rootActivity).GetValue(Activity.WorkflowDefinitionProperty);
54             if (this.originalRootActivity == null)
55                 this.originalRootActivity = rootActivity;
56
57             // Work around: for dynamic update create a clone, without calling initialize for runtime
58             this.clonedRootActivity = (Activity)CloneRootActivity(originalRootActivity);
59
60             // make the tree readonly
61             ApplyDynamicUpdateMode((Activity)this.clonedRootActivity);
62         }
63
64         #endregion
65
66         #region Public members
67         // WhenConditionProperty Get and Set Accessors
68         public static object GetCondition(object dependencyObject)
69         {
70             if (dependencyObject == null)
71                 throw new ArgumentNullException("dependencyObject");
72             if (!(dependencyObject is DependencyObject))
73                 throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(DependencyObject).FullName), "dependencyObject");
74
75             return (dependencyObject as DependencyObject).GetValue(ConditionProperty);
76         }
77
78         public static void SetCondition(object dependencyObject, object value)
79         {
80             if (dependencyObject == null)
81                 throw new ArgumentNullException("dependencyObject");
82             if (!(dependencyObject is DependencyObject))
83                 throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(DependencyObject).FullName), "dependencyObject");
84
85             (dependencyObject as DependencyObject).SetValue(ConditionProperty, value);
86         }
87
88         public CompositeActivity TransientWorkflow
89         {
90             get
91             {
92                 return this.clonedRootActivity as CompositeActivity;
93             }
94         }
95
96         public ValidationErrorCollection Validate()
97         {
98             TypeProvider typeProvider = CreateTypeProvider(this.originalRootActivity);
99
100             // create service provider
101             ServiceContainer serviceContainer = new ServiceContainer();
102             serviceContainer.AddService(typeof(ITypeProvider), typeProvider);
103
104             ValidationManager validationManager = new ValidationManager(serviceContainer);
105             ValidationErrorCollection errors;
106             using (WorkflowCompilationContext.CreateScope(validationManager))
107             {
108                 errors = ValidationHelpers.ValidateObject(validationManager, this.clonedRootActivity);
109             }
110             return XomlCompilerHelper.MorphIntoFriendlyValidationErrors(errors);
111         }
112
113         private void Save()
114         {
115             ValidationErrorCollection errors = Validate();
116             if (errors.HasErrors)
117                 throw new WorkflowValidationFailedException(SR.GetString(SR.Error_CompilerValidationFailed), errors);
118
119             //work around !!!for conditions we do diff 
120             object originalConditions = ((Activity)this.originalRootActivity).GetValue(ConditionTypeConverter.DeclarativeConditionDynamicProp);
121             object changedConditions = ((Activity)this.clonedRootActivity).GetValue(ConditionTypeConverter.DeclarativeConditionDynamicProp);
122             if (null != originalConditions)
123                 this.modelChangeActions.AddRange(((IWorkflowChangeDiff)originalConditions).Diff(originalConditions, changedConditions));
124             else if (null != changedConditions)
125                 this.modelChangeActions.AddRange(((IWorkflowChangeDiff)changedConditions).Diff(originalConditions, changedConditions));
126
127             // diff the process model
128             this.modelChangeActions.AddRange(DiffTrees(this.originalRootActivity as CompositeActivity, this.clonedRootActivity as CompositeActivity));
129
130             // always call it after diff tree, otherwise it turns on the Locked.
131             ReleaseDynamicUpdateMode((Activity)this.clonedRootActivity);
132
133             // cache the change actions into the new workflow definition
134             ArrayList workflowChanges = (ArrayList)((Activity)this.clonedRootActivity).GetValue(WorkflowChanges.WorkflowChangeActionsProperty);
135             if (workflowChanges == null)
136             {
137                 workflowChanges = new ArrayList();
138                 ((Activity)this.clonedRootActivity).SetValue(WorkflowChanges.WorkflowChangeActionsProperty, workflowChanges);
139             }
140
141             workflowChanges.AddRange(this.modelChangeActions);
142             ((Activity)this.clonedRootActivity).SetValue(WorkflowChanges.WorkflowChangeVersionProperty, Guid.NewGuid());
143             this.saved = true;
144
145             // now initialize for runtime
146             ((IDependencyObjectAccessor)this.clonedRootActivity).InitializeDefinitionForRuntime(null);
147         }
148
149         internal void ApplyTo(Activity activity)
150         {
151             if (activity == null)
152                 throw new ArgumentNullException("activity");
153
154             if (activity.Parent != null)
155                 throw new ArgumentException(SR.GetString(SR.Error_RootActivityTypeInvalid), "activity");
156
157             if (activity.RootActivity == null)
158                 throw new InvalidOperationException(SR.GetString(SR.Error_MissingRootActivity));
159
160             if (activity.WorkflowCoreRuntime == null)
161                 throw new InvalidOperationException(SR.GetString(SR.Error_NoRuntimeAvailable));
162
163             if (this.saved)
164                 throw new InvalidOperationException(SR.GetString(SR.Error_TransactionAlreadyApplied));
165
166             if (!CompareWorkflowDefinition((Activity)this.originalRootActivity, (Activity)activity.RootActivity.GetValue(Activity.WorkflowDefinitionProperty)))
167                 throw new ArgumentException(SR.GetString(SR.Error_WorkflowDefinitionModified), "activity");
168
169             this.Save();
170
171             // go up in the chain and then apply changes
172             IWorkflowCoreRuntime workflowCoreRuntime = activity.WorkflowCoreRuntime;
173             if (workflowCoreRuntime.CurrentAtomicActivity != null)
174                 throw new InvalidOperationException(SR.GetString(SR.Error_InsideAtomicScope));
175             bool suspended = workflowCoreRuntime.SuspendInstance(SR.GetString(SR.SuspendReason_WorkflowChange));
176             try
177             {
178                 // collect all context Activities
179                 List<Activity> contextActivities = new List<Activity>();
180                 Queue<Activity> contextActivitiesQueue = new Queue<Activity>();
181                 contextActivitiesQueue.Enqueue(workflowCoreRuntime.RootActivity);
182                 while (contextActivitiesQueue.Count > 0)
183                 {
184                     Activity contextActivity = contextActivitiesQueue.Dequeue();
185                     contextActivities.Add(contextActivity);
186
187                     // enqueue child context Activities
188                     IList<Activity> nestedContextActivities = (IList<Activity>)contextActivity.GetValue(Activity.ActiveExecutionContextsProperty);
189                     if (nestedContextActivities != null)
190                     {
191                         foreach (Activity nestedContextActivity in nestedContextActivities)
192                             contextActivitiesQueue.Enqueue(nestedContextActivity);
193                     }
194                 }
195
196                 // run instance level validations
197                 ValidationErrorCollection validationErrors = new ValidationErrorCollection();
198                 foreach (WorkflowChangeAction changeAction in this.modelChangeActions)
199                 {
200                     if (changeAction is ActivityChangeAction)
201                     {
202                         foreach (Activity contextActivity in contextActivities)
203                         {
204                             // WinOE Bug 16903: Ask the contextActivity itself whether or not it can be removed.
205                             // An activity can not be removed if it's in the executing mode.
206                             if (changeAction is RemovedActivityAction &&
207                                 contextActivity.DottedPath == ((RemovedActivityAction)changeAction).OriginalRemovedActivity.DottedPath)
208                                 validationErrors.AddRange(changeAction.ValidateChanges(contextActivity));
209
210                             // Ask the parent context activity whether or not this child activity can be added or removed.
211                             // The call to TraverseDottedPathFromRoot here should return the parent context activity for this change action.
212                             if (contextActivity.TraverseDottedPathFromRoot(((ActivityChangeAction)changeAction).OwnerActivityDottedPath) != null)
213                                 validationErrors.AddRange(changeAction.ValidateChanges(contextActivity));
214                         }
215                     }
216                 }
217
218                 // if errors then return
219                 if (validationErrors.HasErrors)
220                     throw new WorkflowValidationFailedException(SR.GetString(SR.Error_RuntimeValidationFailed), validationErrors);
221
222                 // verify if workflow can be changed
223                 VerifyWorkflowCanBeChanged(workflowCoreRuntime);
224
225                 // inform workflow runtime
226                 workflowCoreRuntime.OnBeforeDynamicChange(this.modelChangeActions);
227
228                 // set the new Workflow Definition
229                 workflowCoreRuntime.RootActivity.SetValue(Activity.WorkflowDefinitionProperty, this.clonedRootActivity);
230
231                 // apply changes to all context Activities
232                 foreach (Activity contextActivity in contextActivities)
233                 {
234                     // apply change to state reader
235                     foreach (WorkflowChangeAction changeAction in this.modelChangeActions)
236                     {
237                         if (changeAction is ActivityChangeAction)
238                         {
239                             if (contextActivity.TraverseDottedPathFromRoot(((ActivityChangeAction)changeAction).OwnerActivityDottedPath) != null)
240                             {
241                                 bool result = changeAction.ApplyTo(contextActivity);
242                                 Debug.Assert(result, "ApplyTo failed");
243                             }
244                         }
245                     }
246                     // fixup meta properties and notify changes
247                     // if the context activity is the one that's being removed, we do not fixup the meta properties.
248                     Activity clonedActivity = ((Activity)this.clonedRootActivity).GetActivityByName(contextActivity.QualifiedName);
249                     if (clonedActivity != null)
250                         contextActivity.FixUpMetaProperties(clonedActivity);
251                     NotifyChangesToChildExecutors(workflowCoreRuntime, contextActivity, this.modelChangeActions);
252                     NotifyChangesCompletedToChildExecutors(workflowCoreRuntime, contextActivity);
253                 }
254
255                 // inform workflow runtime
256                 workflowCoreRuntime.OnAfterDynamicChange(true, this.modelChangeActions);
257             }
258             catch
259             {
260                 workflowCoreRuntime.OnAfterDynamicChange(false, this.modelChangeActions);
261                 throw;
262             }
263             finally
264             {
265                 if (suspended)
266                     workflowCoreRuntime.Resume();
267             }
268         }
269
270
271         #endregion
272
273         #region Internal Helpers
274         private void OnActivityListChanged(object sender, ActivityCollectionChangeEventArgs e)
275         {
276             if (e.RemovedItems != null)
277             {
278                 foreach (Activity removedActivity in e.RemovedItems)
279                 {
280                     if (removedActivity.Readonly)
281                         ReleaseDynamicUpdateMode(removedActivity);
282                 }
283             }
284         }
285         private void ApplyDynamicUpdateMode(Activity seedActivity)
286         {
287             Queue<Activity> queue = new Queue<Activity>();
288             queue.Enqueue(seedActivity);
289             while (queue.Count > 0)
290             {
291                 Activity activity = queue.Dequeue();
292                 activity.Readonly = true;
293                 activity.DynamicUpdateMode = true;
294                 foreach (DependencyProperty dependencyProperty in activity.MetaDependencyProperties)
295                 {
296                     if (activity.IsBindingSet(dependencyProperty))
297                     {
298                         ActivityBind activityBind = activity.GetBinding(dependencyProperty);
299                         if (activityBind != null)
300                             activityBind.DynamicUpdateMode = true;
301                     }
302                 }
303
304                 if (activity is CompositeActivity)
305                 {
306                     CompositeActivity compositeActivity = activity as CompositeActivity;
307                     compositeActivity.Activities.ListChanged += new EventHandler<ActivityCollectionChangeEventArgs>(this.OnActivityListChanged);
308                     foreach (Activity activity2 in ((CompositeActivity)activity).Activities)
309                         queue.Enqueue(activity2);
310                 }
311             }
312         }
313         private void ReleaseDynamicUpdateMode(Activity seedActivity)
314         {
315             Queue<Activity> queue = new Queue<Activity>();
316             queue.Enqueue(seedActivity);
317             while (queue.Count > 0)
318             {
319                 Activity activity = queue.Dequeue() as Activity;
320                 activity.Readonly = false;
321                 activity.DynamicUpdateMode = false;
322                 foreach (DependencyProperty dependencyProperty in activity.MetaDependencyProperties)
323                 {
324                     if (activity.IsBindingSet(dependencyProperty))
325                     {
326                         ActivityBind activityBind = activity.GetBinding(dependencyProperty);
327                         if (activityBind != null)
328                             activityBind.DynamicUpdateMode = false;
329                     }
330                 }
331                 if (activity is CompositeActivity)
332                 {
333                     CompositeActivity compositeActivity = activity as CompositeActivity;
334                     compositeActivity.Activities.ListChanged -= new EventHandler<ActivityCollectionChangeEventArgs>(this.OnActivityListChanged);
335                     foreach (Activity activity2 in ((CompositeActivity)activity).Activities)
336                         queue.Enqueue(activity2);
337                 }
338             }
339         }
340         private void VerifyWorkflowCanBeChanged(IWorkflowCoreRuntime workflowCoreRuntime)
341         {
342             // check if the update is allowed on this root-activity.
343             ActivityCondition dynamicUpdateCondition = ((Activity)workflowCoreRuntime.RootActivity).GetValue(WorkflowChanges.ConditionProperty) as ActivityCondition;
344             if (dynamicUpdateCondition != null)
345             {
346                 using (workflowCoreRuntime.SetCurrentActivity(workflowCoreRuntime.RootActivity))
347                 {
348                     if (!dynamicUpdateCondition.Evaluate(workflowCoreRuntime.RootActivity, workflowCoreRuntime))
349                         throw new InvalidOperationException(SR.GetString(CultureInfo.CurrentCulture, SR.Error_DynamicUpdateEvaluation, new object[] { workflowCoreRuntime.InstanceID.ToString() }));
350                 }
351             }
352         }
353         private void NotifyChangesCompletedToChildExecutors(IWorkflowCoreRuntime workflowCoreRuntime, Activity contextActivity)
354         {
355             Queue compositeActivities = new Queue();
356             compositeActivities.Enqueue(contextActivity);
357             while (compositeActivities.Count > 0)
358             {
359                 CompositeActivity compositeActivity = compositeActivities.Dequeue() as CompositeActivity;
360                 if (compositeActivity == null || !WorkflowChanges.IsActivityExecutable(compositeActivity))
361                     continue;
362
363                 ISupportWorkflowChanges compositeActivityExecutor = ActivityExecutors.GetActivityExecutor(compositeActivity) as ISupportWorkflowChanges;
364                 if (compositeActivityExecutor != null)
365                 {
366                     using (workflowCoreRuntime.SetCurrentActivity(compositeActivity))
367                     {
368                         using (ActivityExecutionContext executionContext = new ActivityExecutionContext(compositeActivity))
369                             compositeActivityExecutor.OnWorkflowChangesCompleted(executionContext);
370                     }
371                 }
372                 foreach (Activity activity in compositeActivity.Activities)
373                 {
374                     if (activity is CompositeActivity)
375                         compositeActivities.Enqueue(activity);
376                 }
377             }
378         }
379
380         //
381         internal static bool IsActivityExecutable(Activity activity)
382         {
383             if (!activity.Enabled)
384                 return false;
385             if (activity.Parent != null)
386                 return IsActivityExecutable(activity.Parent);
387             return activity.Enabled;
388         }
389
390         private void NotifyChangesToChildExecutors(IWorkflowCoreRuntime workflowCoreRuntime, Activity contextActivity, IList<WorkflowChangeAction> changeActions)
391         {
392             foreach (WorkflowChangeAction action in changeActions)
393             {
394                 if (!(action is ActivityChangeAction))
395                     continue;
396
397                 CompositeActivity ownerActivity = contextActivity.TraverseDottedPathFromRoot(((ActivityChangeAction)action).OwnerActivityDottedPath) as CompositeActivity;
398                 if (ownerActivity == null || !WorkflowChanges.IsActivityExecutable(ownerActivity))
399                     continue;
400
401                 ISupportWorkflowChanges compositeActivityExecutor = ActivityExecutors.GetActivityExecutor(ownerActivity) as ISupportWorkflowChanges;
402                 if (compositeActivityExecutor == null)
403                     throw new ApplicationException(SR.GetString(SR.Error_WorkflowChangesNotSupported, ownerActivity.GetType().FullName));
404
405                 using (workflowCoreRuntime.SetCurrentActivity(ownerActivity))
406                 {
407                     using (ActivityExecutionContext executionContext = new ActivityExecutionContext(ownerActivity))
408                     {
409                         if (action is AddedActivityAction)
410                         {
411                             Activity addedActivity = ownerActivity.Activities[((AddedActivityAction)action).Index];
412                             if (WorkflowChanges.IsActivityExecutable(addedActivity))
413                             {
414                                 addedActivity.OnActivityExecutionContextLoad(executionContext.Activity.RootActivity.WorkflowCoreRuntime);
415                                 executionContext.InitializeActivity(addedActivity);
416                                 compositeActivityExecutor.OnActivityAdded(executionContext, addedActivity);
417                             }
418                         }
419                         else if (action is RemovedActivityAction)
420                         {
421                             RemovedActivityAction removedActivityAction = (RemovedActivityAction)action;
422                             if (WorkflowChanges.IsActivityExecutable(removedActivityAction.OriginalRemovedActivity))
423                             {
424                                 compositeActivityExecutor.OnActivityRemoved(executionContext, removedActivityAction.OriginalRemovedActivity);
425                                 if (removedActivityAction.OriginalRemovedActivity.ExecutionResult != ActivityExecutionResult.Uninitialized)
426                                 {
427                                     removedActivityAction.OriginalRemovedActivity.Uninitialize(executionContext.Activity.RootActivity.WorkflowCoreRuntime);
428                                     removedActivityAction.OriginalRemovedActivity.SetValue(Activity.ExecutionResultProperty, ActivityExecutionResult.Uninitialized);
429                                 }
430                                 removedActivityAction.OriginalRemovedActivity.OnActivityExecutionContextUnload(executionContext.Activity.RootActivity.WorkflowCoreRuntime);
431                                 removedActivityAction.OriginalRemovedActivity.Dispose();
432                             }
433                         }
434                     }
435                 }
436             }
437         }
438         #endregion
439
440         #region Static helpers
441
442         private static bool CompareWorkflowDefinition(Activity originalWorkflowDefinition, Activity currentWorkflowDefinition)
443         {
444             if (originalWorkflowDefinition == currentWorkflowDefinition)
445                 return true;
446
447             if (originalWorkflowDefinition.GetType() != currentWorkflowDefinition.GetType())
448                 return false;
449
450             Guid originalChangeVersion = (Guid)originalWorkflowDefinition.GetValue(WorkflowChanges.WorkflowChangeVersionProperty);
451             Guid currentChangeVersion = (Guid)currentWorkflowDefinition.GetValue(WorkflowChanges.WorkflowChangeVersionProperty);
452             return (originalChangeVersion == currentChangeVersion);
453         }
454
455         private static List<WorkflowChangeAction> DiffTrees(CompositeActivity originalCompositeActivity, CompositeActivity clonedCompositeActivity)
456         {
457             List<WorkflowChangeAction> listChanges = new List<WorkflowChangeAction>();
458             IEnumerator<Activity> clonedActivitiesEnum = clonedCompositeActivity.Activities.GetEnumerator();
459             IEnumerator<Activity> originalActivitiesEnum = originalCompositeActivity.Activities.GetEnumerator();
460             int currentRemoveIndex = 0;
461             while (originalActivitiesEnum.MoveNext())
462             {
463                 bool foundMatching = false;
464                 Activity originalActivity = originalActivitiesEnum.Current;
465                 while (clonedActivitiesEnum.MoveNext())
466                 {
467                     Activity clonedActivity = clonedActivitiesEnum.Current;
468                     if (clonedActivity.Readonly)
469                     {
470                         if (originalActivity.DottedPath == clonedActivity.CachedDottedPath)
471                         {
472                             currentRemoveIndex++;
473                             foundMatching = true;
474                             if (originalActivity is CompositeActivity)
475                                 listChanges.AddRange(DiffTrees(originalActivity as CompositeActivity, clonedActivity as CompositeActivity));
476                             break;
477                         }
478                         else
479                         {
480                             listChanges.Add(new RemovedActivityAction(currentRemoveIndex, originalActivity, clonedCompositeActivity));
481                             while (originalActivitiesEnum.MoveNext())
482                             {
483                                 originalActivity = originalActivitiesEnum.Current;
484                                 if (originalActivity.DottedPath == clonedActivity.CachedDottedPath)
485                                 {
486                                     currentRemoveIndex++;
487                                     foundMatching = true;
488                                     if (originalActivity is CompositeActivity)
489                                         listChanges.AddRange(DiffTrees(originalActivity as CompositeActivity, clonedActivity as CompositeActivity));
490                                     break;
491                                 }
492                                 else
493                                 {
494                                     listChanges.Add(new RemovedActivityAction(currentRemoveIndex, originalActivity, clonedCompositeActivity));
495                                 }
496                             }
497                         }
498                         break;
499                     }
500                     else
501                     {
502                         listChanges.Add(new AddedActivityAction(clonedCompositeActivity, clonedActivity));
503                         currentRemoveIndex++;
504                     }
505                 }
506                 if (!foundMatching)
507                 {
508                     listChanges.Add(new RemovedActivityAction(currentRemoveIndex, originalActivity, clonedCompositeActivity));
509                 }
510             }
511             while (clonedActivitiesEnum.MoveNext())
512                 listChanges.Add(new AddedActivityAction(clonedCompositeActivity, clonedActivitiesEnum.Current));
513             return listChanges;
514         }
515
516         private static Activity CloneRootActivity(Activity originalRootActivity)
517         {
518             // create new definition root
519             string xomlText = originalRootActivity.GetValue(Activity.WorkflowXamlMarkupProperty) as string;
520             string rulesText = null;
521             Activity clonedRootActivity = null;
522             IServiceProvider serviceProvider = originalRootActivity.GetValue(Activity.WorkflowRuntimeProperty) as IServiceProvider;
523             Debug.Assert(serviceProvider != null);
524             if (!string.IsNullOrEmpty(xomlText))
525             {
526                 rulesText = originalRootActivity.GetValue(Activity.WorkflowRulesMarkupProperty) as string;
527                 clonedRootActivity = Activity.OnResolveActivityDefinition(null, xomlText, rulesText, true, false, serviceProvider);
528             }
529             else
530                 clonedRootActivity = Activity.OnResolveActivityDefinition(originalRootActivity.GetType(), null, null, true, false, serviceProvider);
531
532             if (clonedRootActivity == null)
533                 throw new NullReferenceException(SR.GetString(SR.Error_InvalidRootForWorkflowChanges));
534
535             // deserialize change history and apply it to new definition tree
536             ArrayList workflowChanges = (ArrayList)((Activity)originalRootActivity).GetValue(WorkflowChanges.WorkflowChangeActionsProperty);
537             if (workflowChanges != null)
538             {
539                 workflowChanges = CloneWorkflowChangeActions(workflowChanges, originalRootActivity);
540                 if (workflowChanges != null)
541                 {
542                     // apply changes to the shared schedule Defn to get the instance specific copy
543                     foreach (WorkflowChangeAction action in workflowChanges)
544                     {
545                         bool result = action.ApplyTo((Activity)clonedRootActivity);
546                         Debug.Assert(result, "ApplyTo Failed");
547                     }
548                     ((Activity)clonedRootActivity).SetValue(WorkflowChanges.WorkflowChangeActionsProperty, workflowChanges);
549                 }
550             }
551             return clonedRootActivity;
552         }
553
554         private static ArrayList CloneWorkflowChangeActions(ArrayList workflowChanges, Activity rootActivity)
555         {
556             if (workflowChanges == null)
557                 throw new ArgumentNullException("workflowChanges");
558
559             if (rootActivity == null)
560                 throw new ArgumentNullException("rootActivity");
561
562             string dynamicUpdateHistory = null;
563             TypeProvider typeProvider = CreateTypeProvider(rootActivity);
564             ServiceContainer serviceContainer = new ServiceContainer();
565             serviceContainer.AddService(typeof(ITypeProvider), typeProvider);
566             DesignerSerializationManager manager = new DesignerSerializationManager(serviceContainer);
567             WorkflowMarkupSerializer xomlSerializer = new WorkflowMarkupSerializer();
568
569             ArrayList clonedWorkflowChanges = null;
570             // serialize dynamic updates
571             using (manager.CreateSession())
572             {
573                 using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture))
574                 {
575                     using (XmlWriter xmlWriter = Helpers.CreateXmlWriter(sw))
576                     {
577                         WorkflowMarkupSerializationManager xomlSerializationManager = new WorkflowMarkupSerializationManager(manager);
578                         xomlSerializer.Serialize(xomlSerializationManager, xmlWriter, workflowChanges);
579                         dynamicUpdateHistory = sw.ToString();
580                     }
581                 }
582
583                 // deserialize those
584                 using (StringReader sr = new StringReader(dynamicUpdateHistory))
585                 {
586                     using (XmlReader xmlReader = XmlReader.Create(sr))
587                     {
588                         WorkflowMarkupSerializationManager xomlSerializationManager = new WorkflowMarkupSerializationManager(manager);
589                         clonedWorkflowChanges = xomlSerializer.Deserialize(xomlSerializationManager, xmlReader) as ArrayList;
590                     }
591                 }
592             }
593             return clonedWorkflowChanges;
594         }
595
596         internal static TypeProvider CreateTypeProvider(Activity rootActivity)
597         {
598             TypeProvider typeProvider = new TypeProvider(null);
599
600             Type companionType = rootActivity.GetType();
601             typeProvider.SetLocalAssembly(companionType.Assembly);
602             typeProvider.AddAssembly(companionType.Assembly);
603
604             foreach (AssemblyName assemblyName in companionType.Assembly.GetReferencedAssemblies())
605             {
606                 Assembly referencedAssembly = null;
607                 try
608                 {
609                     referencedAssembly = Assembly.Load(assemblyName);
610                     if (referencedAssembly != null)
611                         typeProvider.AddAssembly(referencedAssembly);
612                 }
613                 catch
614                 {
615                 }
616
617                 if (referencedAssembly == null && assemblyName.CodeBase != null)
618                     typeProvider.AddAssemblyReference(assemblyName.CodeBase);
619             }
620             return typeProvider;
621         }
622         #endregion
623     }
624
625     #region WorkflowChangeAction classes
626
627     [DesignerSerializer(typeof(WorkflowMarkupSerializer), typeof(WorkflowMarkupSerializer))]
628     [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
629     public abstract class WorkflowChangeAction
630     {
631         protected internal abstract bool ApplyTo(Activity rootActivity);
632         protected internal abstract ValidationErrorCollection ValidateChanges(Activity activity);
633     }
634
635     [DesignerSerializer(typeof(ActivityChangeActionMarkupSerializer), typeof(WorkflowMarkupSerializer))]
636     [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
637     public abstract class ActivityChangeAction : WorkflowChangeAction
638     {
639         private string ownerActivityDottedPath = string.Empty;
640
641         protected ActivityChangeAction()
642         {
643         }
644
645         protected ActivityChangeAction(CompositeActivity compositeActivity)
646         {
647             if (compositeActivity == null)
648                 throw new ArgumentNullException("compositeActivity");
649
650             this.ownerActivityDottedPath = compositeActivity.DottedPath;
651         }
652
653         [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
654         public string OwnerActivityDottedPath
655         {
656             get
657             {
658                 return this.ownerActivityDottedPath;
659             }
660             internal set
661             {
662                 this.ownerActivityDottedPath = value;
663             }
664         }
665
666         protected internal override ValidationErrorCollection ValidateChanges(Activity contextActivity)
667         {
668             if (contextActivity == null)
669                 throw new ArgumentNullException("contextActivity");
670
671             ValidationErrorCollection errors = new ValidationErrorCollection();
672
673             CompositeActivity ownerActivity = contextActivity.TraverseDottedPathFromRoot(this.OwnerActivityDottedPath) as CompositeActivity;
674             if (ownerActivity != null && WorkflowChanges.IsActivityExecutable(ownerActivity))
675             {
676                 foreach (Validator validator in ComponentDispenser.CreateComponents(ownerActivity.GetType(), typeof(ActivityValidatorAttribute)))
677                 {
678                     ValidationError error = validator.ValidateActivityChange(ownerActivity, this);
679                     if (error != null)
680                         errors.Add(error);
681                 }
682             }
683
684             return errors;
685         }
686     }
687
688     [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
689     public sealed class AddedActivityAction : ActivityChangeAction
690     {
691         private int index = 0;
692         private Activity addedActivity = null;
693
694         public AddedActivityAction()
695         {
696         }
697
698         public AddedActivityAction(CompositeActivity compositeActivity, Activity activityAdded)
699             : base(compositeActivity)
700         {
701             if (compositeActivity == null)
702                 throw new ArgumentNullException("compositeActivity");
703
704             if (activityAdded == null)
705                 throw new ArgumentNullException("activityAdded");
706
707             this.index = (compositeActivity.Activities != null) ? compositeActivity.Activities.IndexOf(activityAdded) : -1;
708             this.addedActivity = activityAdded;
709         }
710         public int Index
711         {
712             get
713             {
714                 return this.index;
715             }
716             internal set
717             {
718                 this.index = value;
719             }
720         }
721
722         public Activity AddedActivity
723         {
724             get
725             {
726                 return this.addedActivity;
727             }
728             internal set
729             {
730                 this.addedActivity = value;
731             }
732         }
733
734         protected internal override bool ApplyTo(Activity rootActivity)
735         {
736             if (rootActivity == null)
737                 throw new ArgumentNullException("rootActivity");
738             if (!(rootActivity is CompositeActivity))
739                 throw new ArgumentException(SR.GetString(SR.Error_RootActivityTypeInvalid), "rootActivity");
740
741             CompositeActivity ownerActivity = rootActivity.TraverseDottedPathFromRoot(this.OwnerActivityDottedPath) as CompositeActivity;
742             if (ownerActivity == null)
743                 return false;
744
745             // !!!work around: 
746             ownerActivity.DynamicUpdateMode = true;
747             CompositeActivity addedActivityOwner = this.addedActivity.Parent;
748             try
749             {
750                 this.addedActivity.SetParent(ownerActivity);
751                 Activity clonedAddedActivity = this.addedActivity;
752                 if (!this.addedActivity.DesignMode)
753                     clonedAddedActivity = this.addedActivity.Clone();
754                 // We need to serialize and deserialize in order to clone during design mode
755                 else
756                 {
757                     TypeProvider typeProvider = WorkflowChanges.CreateTypeProvider(rootActivity);
758                     ServiceContainer serviceContainer = new ServiceContainer();
759                     serviceContainer.AddService(typeof(ITypeProvider), typeProvider);
760                     DesignerSerializationManager manager = new DesignerSerializationManager(serviceContainer);
761                     WorkflowMarkupSerializer xomlSerializer = new WorkflowMarkupSerializer();
762                     string addedActivityText = string.Empty;
763                     // serialize dynamic updates
764                     using (manager.CreateSession())
765                     {
766                         using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture))
767                         {
768                             using (XmlWriter xmlWriter = Helpers.CreateXmlWriter(sw))
769                             {
770                                 WorkflowMarkupSerializationManager xomlSerializationManager = new WorkflowMarkupSerializationManager(manager);
771                                 xomlSerializer.Serialize(xomlSerializationManager, xmlWriter, this.addedActivity);
772                                 addedActivityText = sw.ToString();
773                             }
774                         }
775
776                         // deserialize those
777                         using (StringReader sr = new StringReader(addedActivityText))
778                         {
779                             using (XmlReader xmlReader = XmlReader.Create(sr))
780                             {
781                                 WorkflowMarkupSerializationManager xomlSerializationManager = new WorkflowMarkupSerializationManager(manager);
782                                 clonedAddedActivity = xomlSerializer.Deserialize(xomlSerializationManager, xmlReader) as Activity;
783                             }
784                         }
785                     }
786                     if (clonedAddedActivity == null)
787                         throw new InvalidOperationException(SR.GetString(SR.Error_ApplyDynamicChangeFailed));
788                 }
789                 if (ownerActivity.WorkflowCoreRuntime != null)
790                     ((IDependencyObjectAccessor)clonedAddedActivity).InitializeInstanceForRuntime(ownerActivity.WorkflowCoreRuntime);
791
792                 clonedAddedActivity.SetParent(null);
793                 ownerActivity.Activities.Insert(this.index, clonedAddedActivity);
794             }
795             finally
796             {
797                 this.addedActivity.SetParent(addedActivityOwner);
798                 ownerActivity.DynamicUpdateMode = false;
799             }
800             return true;
801         }
802     }
803
804     [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
805     public sealed class RemovedActivityAction : ActivityChangeAction
806     {
807         private int removedActivityIndex = -1;
808         private Activity originalRemovedActivity = null;
809
810         public RemovedActivityAction()
811         {
812         }
813         public RemovedActivityAction(int removedActivityIndex, Activity originalActivity, CompositeActivity clonedParentActivity)
814             : base(clonedParentActivity)
815         {
816             if (originalActivity == null)
817                 throw new ArgumentNullException("originalActivity");
818             if (clonedParentActivity == null)
819                 throw new ArgumentNullException("clonedParentActivity");
820
821             this.originalRemovedActivity = originalActivity;
822             this.removedActivityIndex = removedActivityIndex;
823         }
824
825         [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
826         public int RemovedActivityIndex
827         {
828             get
829             {
830                 return this.removedActivityIndex;
831             }
832             internal set
833             {
834                 this.removedActivityIndex = value;
835             }
836         }
837         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
838         public Activity OriginalRemovedActivity
839         {
840             get
841             {
842                 return this.originalRemovedActivity;
843             }
844             internal set
845             {
846                 this.originalRemovedActivity = value;
847             }
848         }
849         protected internal override ValidationErrorCollection ValidateChanges(Activity contextActivity)
850         {
851             ValidationErrorCollection errors = base.ValidateChanges(contextActivity);
852             Activity removedActivityInContext = contextActivity.TraverseDottedPathFromRoot(this.originalRemovedActivity.DottedPath);
853             if (WorkflowChanges.IsActivityExecutable(removedActivityInContext) && removedActivityInContext.ExecutionStatus == ActivityExecutionStatus.Executing)
854                 errors.Add(new ValidationError(SR.GetString(SR.Error_RemoveExecutingActivity, this.originalRemovedActivity.QualifiedName), ErrorNumbers.Error_RemoveExecutingActivity));
855             return errors;
856         }
857         protected internal override bool ApplyTo(Activity rootActivity)
858         {
859             if (rootActivity == null)
860                 throw new ArgumentNullException("rootActivity");
861             if (!(rootActivity is CompositeActivity))
862                 throw new ArgumentException(SR.GetString(SR.Error_RootActivityTypeInvalid), "rootActivity");
863
864
865             CompositeActivity ownerActivity = rootActivity.TraverseDottedPathFromRoot(this.OwnerActivityDottedPath) as CompositeActivity;
866             if (ownerActivity == null)
867                 return false;
868
869             if (this.removedActivityIndex >= ownerActivity.Activities.Count)
870                 return false;
871
872             // !!!work around: 
873             ownerActivity.DynamicUpdateMode = true;
874             try
875             {
876                 this.originalRemovedActivity = ownerActivity.Activities[this.removedActivityIndex];
877                 ownerActivity.Activities.RemoveAt(this.removedActivityIndex);
878             }
879             finally
880             {
881                 ownerActivity.DynamicUpdateMode = false;
882             }
883             return true;
884         }
885     }
886     #endregion
887
888     #region Class ActivityChangeActionMarkupSerializer
889     internal sealed class ActivityChangeActionMarkupSerializer : WorkflowMarkupSerializer
890     {
891         protected internal override PropertyInfo[] GetProperties(WorkflowMarkupSerializationManager serializationManager, object obj)
892         {
893             List<PropertyInfo> properties = new List<PropertyInfo>(base.GetProperties(serializationManager, obj));
894
895             //Collect the internal properties, we do this so that activity change action apis don't need to expose unnecessary setters
896             foreach (PropertyInfo property in obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy))
897             {
898                 DesignerSerializationVisibility visibility = Helpers.GetSerializationVisibility(property);
899                 if (visibility != DesignerSerializationVisibility.Hidden && property.GetSetMethod() == null && property.GetSetMethod(true) != null)
900                     properties.Add(property);
901             }
902
903             return properties.ToArray();
904         }
905     }
906     #endregion
907 }