Example #1
0
        internal void ApplyTo(Activity activity)
        {
            if (activity == null)
            {
                throw new ArgumentNullException("activity");
            }

            if (activity.Parent != null)
            {
                throw new ArgumentException(SR.GetString(SR.Error_RootActivityTypeInvalid), "activity");
            }

            if (activity.RootActivity == null)
            {
                throw new InvalidOperationException(SR.GetString(SR.Error_MissingRootActivity));
            }

            if (activity.WorkflowCoreRuntime == null)
            {
                throw new InvalidOperationException(SR.GetString(SR.Error_NoRuntimeAvailable));
            }

            if (this.saved)
            {
                throw new InvalidOperationException(SR.GetString(SR.Error_TransactionAlreadyApplied));
            }

            if (!CompareWorkflowDefinition((Activity)this.originalRootActivity, (Activity)activity.RootActivity.GetValue(Activity.WorkflowDefinitionProperty)))
            {
                throw new ArgumentException(SR.GetString(SR.Error_WorkflowDefinitionModified), "activity");
            }

            this.Save();

            // go up in the chain and then apply changes
            IWorkflowCoreRuntime workflowCoreRuntime = activity.WorkflowCoreRuntime;

            if (workflowCoreRuntime.CurrentAtomicActivity != null)
            {
                throw new InvalidOperationException(SR.GetString(SR.Error_InsideAtomicScope));
            }
            bool suspended = workflowCoreRuntime.SuspendInstance(SR.GetString(SR.SuspendReason_WorkflowChange));

            try
            {
                // collect all context Activities
                List <Activity>  contextActivities      = new List <Activity>();
                Queue <Activity> contextActivitiesQueue = new Queue <Activity>();
                contextActivitiesQueue.Enqueue(workflowCoreRuntime.RootActivity);
                while (contextActivitiesQueue.Count > 0)
                {
                    Activity contextActivity = contextActivitiesQueue.Dequeue();
                    contextActivities.Add(contextActivity);

                    // enqueue child context Activities
                    IList <Activity> nestedContextActivities = (IList <Activity>)contextActivity.GetValue(Activity.ActiveExecutionContextsProperty);
                    if (nestedContextActivities != null)
                    {
                        foreach (Activity nestedContextActivity in nestedContextActivities)
                        {
                            contextActivitiesQueue.Enqueue(nestedContextActivity);
                        }
                    }
                }

                // run instance level validations
                ValidationErrorCollection validationErrors = new ValidationErrorCollection();
                foreach (WorkflowChangeAction changeAction in this.modelChangeActions)
                {
                    if (changeAction is ActivityChangeAction)
                    {
                        foreach (Activity contextActivity in contextActivities)
                        {
                            // WinOE

                            if (changeAction is RemovedActivityAction &&
                                contextActivity.DottedPath == ((RemovedActivityAction)changeAction).OriginalRemovedActivity.DottedPath)
                            {
                                validationErrors.AddRange(changeAction.ValidateChanges(contextActivity));
                            }

                            // Ask the parent context activity whether or not this child activity can be added or removed.
                            // The call to TraverseDottedPathFromRoot here should return the parent context activity for this change action.
                            if (contextActivity.TraverseDottedPathFromRoot(((ActivityChangeAction)changeAction).OwnerActivityDottedPath) != null)
                            {
                                validationErrors.AddRange(changeAction.ValidateChanges(contextActivity));
                            }
                        }
                    }
                }

                // if errors then return
                if (validationErrors.HasErrors)
                {
                    throw new WorkflowValidationFailedException(SR.GetString(SR.Error_RuntimeValidationFailed), validationErrors);
                }

                // verify if workflow can be changed
                VerifyWorkflowCanBeChanged(workflowCoreRuntime);

                // inform workflow runtime
                workflowCoreRuntime.OnBeforeDynamicChange(this.modelChangeActions);

                // set the new Workflow Definition
                workflowCoreRuntime.RootActivity.SetValue(Activity.WorkflowDefinitionProperty, this.clonedRootActivity);

                // apply changes to all context Activities
                foreach (Activity contextActivity in contextActivities)
                {
                    // apply change to state reader
                    foreach (WorkflowChangeAction changeAction in this.modelChangeActions)
                    {
                        if (changeAction is ActivityChangeAction)
                        {
                            if (contextActivity.TraverseDottedPathFromRoot(((ActivityChangeAction)changeAction).OwnerActivityDottedPath) != null)
                            {
                                bool result = changeAction.ApplyTo(contextActivity);
                                Debug.Assert(result, "ApplyTo failed");
                            }
                        }
                    }
                    // fixup meta properties and notify changes
                    // if the context activity is the one that's being removed, we do not fixup the meta properties.
                    Activity clonedActivity = ((Activity)this.clonedRootActivity).GetActivityByName(contextActivity.QualifiedName);
                    if (clonedActivity != null)
                    {
                        contextActivity.FixUpMetaProperties(clonedActivity);
                    }
                    NotifyChangesToChildExecutors(workflowCoreRuntime, contextActivity, this.modelChangeActions);
                    NotifyChangesCompletedToChildExecutors(workflowCoreRuntime, contextActivity);
                }

                // inform workflow runtime
                workflowCoreRuntime.OnAfterDynamicChange(true, this.modelChangeActions);
            }
            catch
            {
                workflowCoreRuntime.OnAfterDynamicChange(false, this.modelChangeActions);
                throw;
            }
            finally
            {
                if (suspended)
                {
                    workflowCoreRuntime.Resume();
                }
            }
        }