//----------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- namespace System.Activities.DynamicUpdate { using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Runtime; using System.Runtime.Serialization; using System.ComponentModel; [DataContract(IsReference = true)] internal class DynamicUpdateMapEntry { static DynamicUpdateMapEntry dummyMapEntry = new DynamicUpdateMapEntry(-1, -1); DynamicUpdateMap implementationUpdateMap; int oldActivityId; int newActivityId; public DynamicUpdateMapEntry(int oldActivityId, int newActivityId) { this.OldActivityId = oldActivityId; this.NewActivityId = newActivityId; } // this is a dummy map entry to be used for creating a NativeActivityUpdateContext // for calling UpdateInstance() on activities without map entries. // the OldActivityId and NewActivityId of this dummy map entry are invalid, // and should not be used anywhere except for creating NativeActivityUpdateContext. internal static DynamicUpdateMapEntry DummyMapEntry { get { return dummyMapEntry; } } public int OldActivityId { get { return this.oldActivityId; } private set { this.oldActivityId = value; } } public int NewActivityId { get { return this.newActivityId; } private set { this.newActivityId = value; } } [DataMember(EmitDefaultValue = false)] public DynamicUpdateMapEntry Parent { get; set; } // Only set when IsRemoval == true && IsParentRemovedOrBlock == false [DataMember(EmitDefaultValue = false)] public string DisplayName { get; set; } [DataMember(EmitDefaultValue = false)] public UpdateBlockedReason BlockReason { get; set; } [DataMember(EmitDefaultValue = false)] public string BlockReasonMessage { get; set; } public bool IsRuntimeUpdateBlocked { get { return BlockReason != UpdateBlockedReason.NotBlocked; } } [DataMember(EmitDefaultValue = false)] public bool IsUpdateBlockedByUpdateAuthor { get; set; } public bool IsParentRemovedOrBlocked { get { for (DynamicUpdateMapEntry parent = this.Parent; parent != null; parent = parent.Parent) { if (parent.IsRemoval || parent.IsRuntimeUpdateBlocked || parent.IsUpdateBlockedByUpdateAuthor) { return true; } } return false; } } [DataMember(EmitDefaultValue = false)] public IDictionary SavedOriginalValues { get; set; } [DataMember(EmitDefaultValue = false)] public object SavedOriginalValueFromParent { get; set; } [DataMember(EmitDefaultValue = false)] public EnvironmentUpdateMap EnvironmentUpdateMap { get; set; } public DynamicUpdateMap ImplementationUpdateMap { get { return this.implementationUpdateMap; } internal set { this.implementationUpdateMap = value; } } [DataMember(EmitDefaultValue = false, Name = "implementationUpdateMap")] internal DynamicUpdateMap SerializedImplementationUpdateMap { get { return this.implementationUpdateMap; } set { this.implementationUpdateMap = value; } } [DataMember(EmitDefaultValue = false, Name = "OldActivityId")] internal int SerializedOldActivityId { get { return this.OldActivityId; } set { this.OldActivityId = value; } } [DataMember(EmitDefaultValue = false, Name = "NewActivityId")] internal int SerializedNewActivityId { get { return this.NewActivityId; } set { this.NewActivityId = value; } } internal bool IsIdChange { get { return this.NewActivityId > 0 && this.OldActivityId > 0 && this.NewActivityId != this.OldActivityId; } } internal bool IsRemoval { get { return this.NewActivityId <= 0 && this.OldActivityId > 0; } } internal bool HasEnvironmentUpdates { get { return this.EnvironmentUpdateMap != null; } } 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 IDictionary Merge(IDictionary first, IDictionary second) { if (first == null || second == null) { return first ?? second; } Dictionary result = new Dictionary(first); foreach (KeyValuePair pair in second) { if (!result.ContainsKey(pair.Key)) { result.Add(pair.Key, pair.Value); } } return result; } 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 }; } } }