예제 #1
0
        private bool CanApplyUpdateWhileRunning(Activity activity, bool isInNewDefinition)
        {
            var currentActivity = activity;
            var rootIdSpace     = activity.MemberOf;

            do
            {
                DynamicUpdateMapEntry entry = null;
                if (isInNewDefinition)
                {
                    this.map.TryGetUpdateEntryByNewId(currentActivity.InternalId, out entry);
                }
                else if (currentActivity.MemberOf == rootIdSpace)
                {
                    this.map.TryGetUpdateEntry(currentActivity.InternalId, out entry);
                }

                if (entry != null &&
                    (entry.NewActivityId < 1 ||
                     entry.IsRuntimeUpdateBlocked ||
                     entry.IsUpdateBlockedByUpdateAuthor))
                {
                    return(false);
                }

                currentActivity = currentActivity.Parent;
            }while (currentActivity != null && currentActivity.MemberOf == rootIdSpace);

            return(true);
        }
예제 #2
0
        private Activity MatchNewToOld(Activity newActivity, out DynamicUpdateMapEntry entry)
        {
            if (this.map.TryGetUpdateEntryByNewId(newActivity.InternalId, out entry))
            {
                var rootIdSpace = this.map.IsForImplementation ? this.originalWorkflowDefinition.ParentOf : this.originalWorkflowDefinition.MemberOf;
                if (rootIdSpace != null)
                {
                    return(rootIdSpace[entry.OldActivityId]);
                }
            }

            return(null);
        }
예제 #3
0
        private Activity MatchOldToNew(Activity oldActivity, out DynamicUpdateMapEntry entry)
        {
            if (this.map.TryGetUpdateEntry(oldActivity.InternalId, out entry) && entry.NewActivityId > 0)
            {
                var rootIdSpace = this.map.IsForImplementation ? this.updatedWorkflowDefinition.ParentOf : this.updatedWorkflowDefinition.MemberOf;
                if (rootIdSpace != null)
                {
                    return(rootIdSpace[entry.NewActivityId]);
                }
            }

            return(null);
        }
예제 #4
0
        internal bool TryGetUpdateEntry(int oldId, out DynamicUpdateMapEntry entry)
        {
            if (this.entries != null && this.entries.Count > 0)
            {
                if (this.entries.Contains(oldId))
                {
                    entry = this.entries[oldId];
                    return(true);
                }
            }

            entry = null;
            return(false);
        }
예제 #5
0
 internal DynamicUpdateMapEntry Clone(DynamicUpdateMapEntry newParent)
 {
     return(new DynamicUpdateMapEntry(this.OldActivityId, this.NewActivityId)
     {
         DisplayName = this.DisplayName,
         EnvironmentUpdateMap = this.EnvironmentUpdateMap,
         ImplementationUpdateMap = this.ImplementationUpdateMap,
         BlockReason = this.BlockReason,
         BlockReasonMessage = this.BlockReasonMessage,
         IsUpdateBlockedByUpdateAuthor = this.IsUpdateBlockedByUpdateAuthor,
         Parent = newParent,
         SavedOriginalValues = this.SavedOriginalValues,
         SavedOriginalValueFromParent = this.SavedOriginalValueFromParent
     });
 }
예제 #6
0
        internal bool TryGetUpdateEntryByNewId(int newId, out DynamicUpdateMapEntry entry)
        {
            Fx.Assert(!this.IsNoChanges, "This method is never supposed to be called on the NoChanges map.");

            entry = null;

            for (int i = 0; i < this.Entries.Count; i++)
            {
                DynamicUpdateMapEntry currentEntry = this.Entries[i];
                if (currentEntry.NewActivityId == newId)
                {
                    entry = currentEntry;
                    return(true);
                }
            }
            return(false);
        }
예제 #7
0
        internal static DynamicUpdateMapEntry Merge(DynamicUpdateMapEntry first, DynamicUpdateMapEntry second,
                                                    DynamicUpdateMapEntry newParent, DynamicUpdateMap.MergeErrorContext errorContext)
        {
            Fx.Assert(first.NewActivityId == second.OldActivityId, "Merging mismatched entries");
            Fx.Assert((first.Parent == null && second.Parent == null) || (first.Parent.NewActivityId == second.Parent.OldActivityId), "Merging mismatched parents");

            var result = new DynamicUpdateMapEntry(first.OldActivityId, second.NewActivityId)
            {
                Parent = newParent
            };

            if (second.IsRemoval)
            {
                if (!result.IsParentRemovedOrBlocked)
                {
                    result.DisplayName = second.DisplayName;
                }
            }
            else
            {
                result.SavedOriginalValues          = Merge(first.SavedOriginalValues, second.SavedOriginalValues);
                result.SavedOriginalValueFromParent = first.SavedOriginalValueFromParent ?? second.SavedOriginalValueFromParent;
                if (first.BlockReason == UpdateBlockedReason.NotBlocked)
                {
                    result.BlockReason        = second.BlockReason;
                    result.BlockReasonMessage = second.BlockReasonMessage;
                }
                else
                {
                    result.BlockReason        = first.BlockReason;
                    result.BlockReasonMessage = second.BlockReasonMessage;
                }
                result.IsUpdateBlockedByUpdateAuthor = first.IsUpdateBlockedByUpdateAuthor || second.IsUpdateBlockedByUpdateAuthor;

                errorContext.PushIdSpace(result.NewActivityId);
                result.EnvironmentUpdateMap = EnvironmentUpdateMap.Merge(first.EnvironmentUpdateMap, second.EnvironmentUpdateMap, errorContext);
                if (!result.IsRuntimeUpdateBlocked && !result.IsUpdateBlockedByUpdateAuthor && !result.IsParentRemovedOrBlocked)
                {
                    result.ImplementationUpdateMap = DynamicUpdateMap.Merge(first.ImplementationUpdateMap, second.ImplementationUpdateMap, errorContext);
                }
                errorContext.PopIdSpace();
            };

            return(result);
        }
예제 #8
0
        internal static DynamicUpdateMap Merge(DynamicUpdateMap first, DynamicUpdateMap second, MergeErrorContext errorContext)
        {
            if (first == null || second == null)
            {
                return(first ?? second);
            }

            if (first.IsNoChanges || second.IsNoChanges)
            {
                // DynamicUpdateMap.NoChanges has zero members, so we need to special-case it here.
                return(first.IsNoChanges ? second : first);
            }

            ThrowIfMapsIncompatible(first, second, errorContext);

            DynamicUpdateMap result = new DynamicUpdateMap
            {
                IsForImplementation      = first.IsForImplementation,
                NewDefinitionMemberCount = second.NewDefinitionMemberCount,
                ArgumentsAreUnknown      = first.ArgumentsAreUnknown && second.ArgumentsAreUnknown,
                oldArguments             = first.ArgumentsAreUnknown ? second.oldArguments : first.oldArguments,
                newArguments             = second.ArgumentsAreUnknown ? first.newArguments : second.newArguments
            };

            foreach (DynamicUpdateMapEntry firstEntry in first.Entries)
            {
                DynamicUpdateMapEntry parent = null;
                if (firstEntry.Parent != null)
                {
                    result.TryGetUpdateEntry(firstEntry.Parent.OldActivityId, out parent);
                }

                if (firstEntry.IsRemoval)
                {
                    result.AddEntry(firstEntry.Clone(parent));
                }
                else
                {
                    DynamicUpdateMapEntry secondEntry = second.entries[firstEntry.NewActivityId];
                    result.AddEntry(DynamicUpdateMapEntry.Merge(firstEntry, secondEntry, parent, errorContext));
                }
            }

            return(result);
        }
        private Activity MatchNewToOld(Activity newActivity, out DynamicUpdateMapEntry entry)
        {
            entry = null;
            if (this.map.TryGetUpdateEntryByNewId(newActivity.InternalId, out entry))
            {
                IdSpace rootIdSpace;
                if (this.map.IsForImplementation)
                {
                    rootIdSpace = this.originalWorkflowDefinition.ParentOf;                    
                }
                else
                {
                    rootIdSpace = this.originalWorkflowDefinition.MemberOf;
                }

                if (rootIdSpace != null)
                {
                    return rootIdSpace[entry.OldActivityId];
                }        
            }            

            return null;
        }
 internal DynamicUpdateMapEntry Clone(DynamicUpdateMapEntry newParent)
 {
     return new DynamicUpdateMapEntry(this.OldActivityId, this.NewActivityId)
     {
         DisplayName = this.DisplayName,
         EnvironmentUpdateMap = this.EnvironmentUpdateMap,
         ImplementationUpdateMap = this.ImplementationUpdateMap,
         BlockReason = this.BlockReason,
         BlockReasonMessage = this.BlockReasonMessage,
         IsUpdateBlockedByUpdateAuthor = this.IsUpdateBlockedByUpdateAuthor,
         Parent = newParent,
         SavedOriginalValues = this.SavedOriginalValues,
         SavedOriginalValueFromParent = this.SavedOriginalValueFromParent
     };
 }
        internal static DynamicUpdateMapEntry Merge(DynamicUpdateMapEntry first, DynamicUpdateMapEntry second,
            DynamicUpdateMapEntry newParent, DynamicUpdateMap.MergeErrorContext errorContext)
        {
            Fx.Assert(first.NewActivityId == second.OldActivityId, "Merging mismatched entries");
            Fx.Assert((first.Parent == null && second.Parent == null) || (first.Parent.NewActivityId == second.Parent.OldActivityId), "Merging mismatched parents");

            DynamicUpdateMapEntry result = new DynamicUpdateMapEntry(first.OldActivityId, second.NewActivityId)
            {
                Parent = newParent
            };

            if (second.IsRemoval)
            {
                if (!result.IsParentRemovedOrBlocked)
                {
                    result.DisplayName = second.DisplayName;
                }
            }
            else
            {
                result.SavedOriginalValues = Merge(first.SavedOriginalValues, second.SavedOriginalValues);
                result.SavedOriginalValueFromParent = first.SavedOriginalValueFromParent ?? second.SavedOriginalValueFromParent;
                if (first.BlockReason == UpdateBlockedReason.NotBlocked)
                {
                    result.BlockReason = second.BlockReason;
                    result.BlockReasonMessage = second.BlockReasonMessage;
                }
                else
                {
                    result.BlockReason = first.BlockReason;
                    result.BlockReasonMessage = second.BlockReasonMessage;
                }
                result.IsUpdateBlockedByUpdateAuthor = first.IsUpdateBlockedByUpdateAuthor || second.IsUpdateBlockedByUpdateAuthor;

                errorContext.PushIdSpace(result.NewActivityId);
                result.EnvironmentUpdateMap = EnvironmentUpdateMap.Merge(first.EnvironmentUpdateMap, second.EnvironmentUpdateMap, errorContext);
                if (!result.IsRuntimeUpdateBlocked && !result.IsUpdateBlockedByUpdateAuthor && !result.IsParentRemovedOrBlocked)
                {
                    result.ImplementationUpdateMap = DynamicUpdateMap.Merge(first.ImplementationUpdateMap, second.ImplementationUpdateMap, errorContext);
                }
                errorContext.PopIdSpace();
            };

            return result;
        }
예제 #12
0
            bool TryMatchingArguments(DynamicUpdateMapEntry entry, Activity originalActivity, Activity currentActivity)
            {
                // now, let's try creating argument entries
                IList <ArgumentInfo> oldArguments = ArgumentInfo.List(originalActivity);

                this.nestedFinalizer.CreateArgumentEntries(entry, currentActivity.RuntimeArguments, oldArguments);
                if (entry.HasEnvironmentUpdates)
                {
                    if (entry.EnvironmentUpdateMap.HasArgumentEntries)
                    {
                        foreach (EnvironmentUpdateMapEntry argumentEntry in entry.EnvironmentUpdateMap.ArgumentEntries)
                        {
                            if (!argumentEntry.IsAddition)
                            {
                                // if it is a matching argument pair,
                                // let's add them to the lists for further matching process.
                                RuntimeArgument originalArg = originalActivity.RuntimeArguments[argumentEntry.OldOffset];
                                RuntimeArgument updatedArg  = currentActivity.RuntimeArguments[argumentEntry.NewOffset];
                                if (!this.TryPreparingArgumentExpressions(originalArg, updatedArg))
                                {
                                    return(false);
                                }
                            }
                        }
                    }

                    // we need to also visit subtrees of Expressions of removed arguments
                    IList <ArgumentInfo> newArgumentInfos = ArgumentInfo.List(currentActivity);
                    foreach (RuntimeArgument oldRuntimeArgument in originalActivity.RuntimeArguments)
                    {
                        if (newArgumentInfos.IndexOf(new ArgumentInfo(oldRuntimeArgument)) == EnvironmentUpdateMapEntry.NonExistent)
                        {
                            // this is a removed argument.
                            if (oldRuntimeArgument.IsBound && oldRuntimeArgument.BoundArgument.Expression != null && oldRuntimeArgument.BoundArgument.Expression.MemberOf == originalActivity.MemberOf)
                            {
                                // create an entry for removal of this expression
                                this.privateMap.AddEntry(new DynamicUpdateMapEntry(oldRuntimeArgument.BoundArgument.Expression.InternalId, 0));
                            }
                        }
                    }

                    DynamicUpdateMapBuilder.Finalizer.FillEnvironmentMapMemberCounts(entry.EnvironmentUpdateMap, currentActivity, originalActivity, oldArguments);
                    this.argumentChangeDetected = true;
                }
                else if (currentActivity.RuntimeArguments != null && currentActivity.RuntimeArguments.Count > 0)
                {
                    Fx.Assert(currentActivity.RuntimeArguments.Count == originalActivity.RuntimeArguments.Count, "RuntimeArguments.Count for both currentActivity and originalActivity must be equal.");

                    // if we are here, we know RuntimeArguments matched between currentActivity and originalActivity
                    // but we still need to prepare their Expressions for matching
                    for (int i = 0; i < currentActivity.RuntimeArguments.Count; i++)
                    {
                        if (!this.TryPreparingArgumentExpressions(originalActivity.RuntimeArguments[i], currentActivity.RuntimeArguments[i]))
                        {
                            return(false);
                        }
                    }
                }

                if (entry.IsRuntimeUpdateBlocked)
                {
                    entry.EnvironmentUpdateMap = null;
                }

                return(true);
            }
예제 #13
0
            public bool Match(out DynamicUpdateMap argumentChangesMap)
            {
                argumentChangesMap = null;

                int  nextOriginalSubrootId   = 0;
                int  nextUpdatedSubrootId    = 0;
                bool allSubtreeRootsEnqueued = false;

                // enqueue all subtree root pairs first
                while (!allSubtreeRootsEnqueued)
                {
                    nextOriginalSubrootId = GetIndexOfNextSubtreeRoot(this.originalPrivateIdSpace, nextOriginalSubrootId);
                    nextUpdatedSubrootId  = GetIndexOfNextSubtreeRoot(this.updatedPrivateIdSpace, nextUpdatedSubrootId);

                    if (nextOriginalSubrootId != -1 && nextUpdatedSubrootId != -1)
                    {
                        // found next disjoint subtree pair to match
                        this.PrepareToMatchSubtree(this.updatedPrivateIdSpace[nextUpdatedSubrootId], this.originalPrivateIdSpace[nextOriginalSubrootId]);
                    }
                    else if (nextOriginalSubrootId == -1 && nextUpdatedSubrootId == -1)
                    {
                        // there are no more subtree root pair to process.
                        allSubtreeRootsEnqueued = true;
                    }
                    else
                    {
                        // something other than Arguments must have changed
                        return(false);
                    }
                }

                while (this.matchedActivities.Count > 0)
                {
                    Tuple <Activity, Activity> pair = this.matchedActivities.Dequeue();
                    Activity originalActivity       = pair.Item1;
                    Activity currentActivity        = pair.Item2;

                    Fx.Assert(originalActivity.MemberOf == this.originalPrivateIdSpace && currentActivity.MemberOf == this.updatedPrivateIdSpace, "neither activities must be a reference.");

                    if (currentActivity.GetType() != originalActivity.GetType() || currentActivity.RelationshipToParent != originalActivity.RelationshipToParent)
                    {
                        return(false);
                    }

                    // there is no need to perform CompareChildEquality since we already compare ActivityId and activity.GetType() as above for all activities in the IdSpace, and check on the collection count
                    if (!ActivityComparer.ListEquals(
                            ActivityComparer.GetDeclaredChildren(currentActivity.Children, currentActivity),
                            ActivityComparer.GetDeclaredChildren(originalActivity.Children, originalActivity),
                            this.AddEqualChildren))
                    {
                        return(false);
                    }

                    // there is no need to perform CompareChildEquality since we already compare ActivityId and activity.GetType() as above for all activities in the IdSpace, and check on the collection count
                    if (!ActivityComparer.ListEquals(
                            ActivityComparer.GetDeclaredChildren(currentActivity.ImportedChildren, currentActivity),
                            ActivityComparer.GetDeclaredChildren(originalActivity.ImportedChildren, originalActivity),
                            this.AddEqualChildren))
                    {
                        return(false);
                    }

                    if (!ActivityComparer.ListEquals <ActivityDelegate>(
                            ActivityComparer.GetDeclaredDelegates(currentActivity.Delegates, currentActivity),
                            ActivityComparer.GetDeclaredDelegates(originalActivity.Delegates, originalActivity),
                            this.CompareDelegateEqualityAndAddActivitiesPair))
                    {
                        return(false);
                    }

                    if (!ActivityComparer.ListEquals <ActivityDelegate>(
                            ActivityComparer.GetDeclaredDelegates(currentActivity.ImportedDelegates, currentActivity),
                            ActivityComparer.GetDeclaredDelegates(originalActivity.ImportedDelegates, originalActivity),
                            this.CompareDelegateEqualityAndAddActivitiesPair))
                    {
                        return(false);
                    }

                    if (!ActivityComparer.ListEquals <Variable>(currentActivity.RuntimeVariables, originalActivity.RuntimeVariables, this.CompareVariableEqualityAndAddActivitiesPair))
                    {
                        return(false);
                    }

                    // with all runtime metadata except arguments matching,
                    // the current activities pair qualifies as a matching entry
                    // let's create an entry
                    DynamicUpdateMapEntry entry = new DynamicUpdateMapEntry(originalActivity.InternalId, currentActivity.InternalId);
                    this.privateMap.AddEntry(entry);

                    if (!this.TryMatchingArguments(entry, originalActivity, currentActivity))
                    {
                        return(false);
                    }
                }

                // there are no more activities-pair to process.
                // if we are here, it means we have successfully matched the private IdSpace pair
                if (this.argumentChangeDetected)
                {
                    // return the generated map only if we have argument entries
                    argumentChangesMap = this.privateMap;
                }

                return(true);
            }
        private Activity MatchOldToNew(Activity oldActivity, out DynamicUpdateMapEntry entry)
        {
            entry = null;

            if (this.map.TryGetUpdateEntry(oldActivity.InternalId, out entry) && entry.NewActivityId > 0)
            {
                IdSpace rootIdSpace;
                if (this.map.IsForImplementation)
                {
                    rootIdSpace = this.updatedWorkflowDefinition.ParentOf;                    
                }
                else
                {
                    rootIdSpace = this.updatedWorkflowDefinition.MemberOf;
                }

                if (rootIdSpace != null)
                {
                    return rootIdSpace[entry.NewActivityId];
                }        
            }

            return null;
        }
예제 #15
0
 internal void AddEntry(DynamicUpdateMapEntry entry)
 {
     this.Entries.Add(entry);
 }