private bool CanApplyUpdateWhileRunning(Activity activity, bool isInNewDefinition) { Activity currentActivity = activity; IdSpace 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); }
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); }
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 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); }
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); }
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); }
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); }
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); }
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); }
internal void AddEntry(DynamicUpdateMapEntry entry) { this.Entries.Add(entry); }