You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@@ -0,0 +1,161 @@
|
||||
// <copyright>
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace System.Activities.DynamicUpdate
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Runtime;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
[Serializable]
|
||||
[DataContract]
|
||||
public class ActivityBlockingUpdate
|
||||
{
|
||||
[NonSerialized]
|
||||
private Activity activity;
|
||||
|
||||
string activityInstanceId;
|
||||
string originalActivityId;
|
||||
string updatedActivityId;
|
||||
string reason;
|
||||
|
||||
public ActivityBlockingUpdate(Activity activity, string originalActivityId, string reason)
|
||||
: this(activity, originalActivityId, reason, null)
|
||||
{
|
||||
}
|
||||
|
||||
public ActivityBlockingUpdate(Activity activity, string originalActivityId, string reason, string activityInstanceId)
|
||||
{
|
||||
this.activity = activity;
|
||||
this.Reason = reason;
|
||||
this.OriginalActivityId = originalActivityId;
|
||||
this.ActivityInstanceId = activityInstanceId;
|
||||
if (activity != null)
|
||||
{
|
||||
this.UpdatedActivityId = activity.Id;
|
||||
}
|
||||
}
|
||||
|
||||
public ActivityBlockingUpdate(string updatedActivityId, string originalActivityId, string reason)
|
||||
: this(updatedActivityId, originalActivityId, reason, null)
|
||||
{
|
||||
}
|
||||
|
||||
public ActivityBlockingUpdate(string updatedActivityId, string originalActivityId, string reason, string activityInstanceId)
|
||||
{
|
||||
this.UpdatedActivityId = updatedActivityId;
|
||||
this.OriginalActivityId = originalActivityId;
|
||||
this.ActivityInstanceId = activityInstanceId;
|
||||
this.Reason = reason;
|
||||
}
|
||||
|
||||
public Activity Activity
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.activity;
|
||||
}
|
||||
}
|
||||
|
||||
public string ActivityInstanceId
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.activityInstanceId;
|
||||
}
|
||||
private set
|
||||
{
|
||||
this.activityInstanceId = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string OriginalActivityId
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.originalActivityId;
|
||||
}
|
||||
private set
|
||||
{
|
||||
this.originalActivityId = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string UpdatedActivityId
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.updatedActivityId;
|
||||
}
|
||||
private set
|
||||
{
|
||||
this.updatedActivityId = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string Reason
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.reason;
|
||||
}
|
||||
private set
|
||||
{
|
||||
this.reason = value;
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false, Name = "ActivityInstanceId")]
|
||||
internal string SerializedActivityInstanceId
|
||||
{
|
||||
get { return this.ActivityInstanceId; }
|
||||
set { this.ActivityInstanceId = value; }
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false, Name = "OriginalActivityId")]
|
||||
internal string SerializedOriginalActivityId
|
||||
{
|
||||
get { return this.OriginalActivityId; }
|
||||
set { this.OriginalActivityId = value; }
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false, Name = "UpdatedActivityId")]
|
||||
internal string SerializedUpdatedActivityId
|
||||
{
|
||||
get { return this.UpdatedActivityId; }
|
||||
set { this.UpdatedActivityId = value; }
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false, Name = "Reason")]
|
||||
internal string SerializedReason
|
||||
{
|
||||
get { return this.Reason; }
|
||||
set { this.Reason = value; }
|
||||
}
|
||||
|
||||
internal static void AddBlockingActivity(ref Collection<ActivityBlockingUpdate> blockingActivities, Activity activity, string originalActivityId, string reason, string activityInstanceId)
|
||||
{
|
||||
if (blockingActivities == null)
|
||||
{
|
||||
blockingActivities = new Collection<ActivityBlockingUpdate>();
|
||||
}
|
||||
|
||||
ActivityBlockingUpdate blockingActivity = new ActivityBlockingUpdate(activity, originalActivityId, reason, activityInstanceId);
|
||||
blockingActivities.Add(blockingActivity);
|
||||
}
|
||||
|
||||
internal static void AddBlockingActivity(ref Collection<ActivityBlockingUpdate> blockingActivities, string updatedActivityId, string originalActivityId, string reason, string activityInstanceId)
|
||||
{
|
||||
if (blockingActivities == null)
|
||||
{
|
||||
blockingActivities = new Collection<ActivityBlockingUpdate>();
|
||||
}
|
||||
|
||||
ActivityBlockingUpdate blockingActivity = new ActivityBlockingUpdate(updatedActivityId, originalActivityId, reason, activityInstanceId);
|
||||
blockingActivities.Add(blockingActivity);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,331 @@
|
||||
// <copyright>
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace System.Activities.DynamicUpdate
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
|
||||
[DataContract]
|
||||
internal class ArgumentInfo
|
||||
{
|
||||
// the following two fields are never to be serialized.
|
||||
private Type type;
|
||||
private bool HasGetTypeBeenAttempted;
|
||||
|
||||
string versionlessAssemblyQualifiedTypeName;
|
||||
string name;
|
||||
string fullAssemblyQualifiedTypeName;
|
||||
ArgumentDirection direction;
|
||||
|
||||
public ArgumentInfo(RuntimeArgument argument)
|
||||
{
|
||||
this.Name = argument.Name;
|
||||
|
||||
Fx.Assert(argument.Type != null, "argument Type must not be null.");
|
||||
this.Type = argument.Type;
|
||||
this.HasGetTypeBeenAttempted = true;
|
||||
|
||||
this.FullAssemblyQualifiedTypeName = this.Type.AssemblyQualifiedName;
|
||||
|
||||
// this versionless assembly-qualified type name causes types of different versions
|
||||
// to be considered equal for the sake of argument matching.
|
||||
// Serializing the argument type info in a string format allows
|
||||
// the map to be loaded into environment in which the types may not be available.
|
||||
this.versionlessAssemblyQualifiedTypeName = GenerateVersionlessAssemblyQualifiedTypeName(argument.Type);
|
||||
|
||||
this.Direction = argument.Direction;
|
||||
}
|
||||
|
||||
private Type Type
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.type == null && !this.HasGetTypeBeenAttempted)
|
||||
{
|
||||
// For every deserialized ArgumentInfo, we are here only the very first call to the property getter.
|
||||
this.HasGetTypeBeenAttempted = true;
|
||||
try
|
||||
{
|
||||
this.type = Type.GetType(this.FullAssemblyQualifiedTypeName, false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e is TypeLoadException || e is FileNotFoundException || e is FileLoadException || e is ArgumentException)
|
||||
{
|
||||
this.type = null;
|
||||
FxTrace.Exception.AsWarning(e);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.type;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.type = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.name;
|
||||
}
|
||||
private set
|
||||
{
|
||||
this.name = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string FullAssemblyQualifiedTypeName
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.fullAssemblyQualifiedTypeName;
|
||||
}
|
||||
private set
|
||||
{
|
||||
this.fullAssemblyQualifiedTypeName = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ArgumentDirection Direction
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.direction;
|
||||
}
|
||||
private set
|
||||
{
|
||||
this.direction = value;
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false, Name = "VersionlessAssemblyQualifiedTypeName")]
|
||||
internal string SerializedVersionlessAssemblyQualifiedTypeName
|
||||
{
|
||||
get { return this.versionlessAssemblyQualifiedTypeName; }
|
||||
set { this.versionlessAssemblyQualifiedTypeName = value; }
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false, Name = "Name")]
|
||||
internal string SerializedName
|
||||
{
|
||||
get { return this.Name; }
|
||||
set { this.Name = value; }
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false, Name = "FullAssemblyQualifiedTypeName")]
|
||||
internal string SerializedFullAssemblyQualifiedTypeName
|
||||
{
|
||||
get { return this.FullAssemblyQualifiedTypeName; }
|
||||
set { this.FullAssemblyQualifiedTypeName = value; }
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false, Name = "Direction")]
|
||||
internal ArgumentDirection SerializedDirection
|
||||
{
|
||||
get { return this.Direction; }
|
||||
set { this.Direction = value; }
|
||||
}
|
||||
|
||||
private static bool TypeEquals(ArgumentInfo left, ArgumentInfo right)
|
||||
{
|
||||
Fx.Assert(left != null && right != null, "both left and right must not be null.");
|
||||
|
||||
if (left.versionlessAssemblyQualifiedTypeName == right.versionlessAssemblyQualifiedTypeName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Try to determine if the two argument types are in fact the same due to one being a TypeForwardedTo type to the other.
|
||||
// When forwarded types are used, it is expected that all the assemblies involved in type forwarding to be always available,
|
||||
// whether during map calcuation, during implementation map rollup, or during merging of multiple maps.
|
||||
//
|
||||
if (left.Type != null && right.Type != null && left.Type == right.Type)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool Equals(ArgumentInfo left, ArgumentInfo right)
|
||||
{
|
||||
if (left == null)
|
||||
{
|
||||
return right == null;
|
||||
}
|
||||
|
||||
return right != null &&
|
||||
left.Name == right.Name && TypeEquals(left, right) && left.Direction == right.Direction;
|
||||
}
|
||||
|
||||
public static IList<ArgumentInfo> List(Activity activity)
|
||||
{
|
||||
if (activity.RuntimeArguments == null)
|
||||
{
|
||||
return new List<ArgumentInfo>();
|
||||
}
|
||||
|
||||
return (from r in activity.RuntimeArguments select new ArgumentInfo(r)).ToList();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
ArgumentInfo operand = obj as ArgumentInfo;
|
||||
return Equals(this, operand);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
|
||||
// generate assembly-qualified type name without assembly's version, culture and public token info
|
||||
static string GenerateVersionlessAssemblyQualifiedTypeName(Type type)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
BuildTypeSpec(sb, type);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
static void BuildTypeSpec(StringBuilder sb, Type type)
|
||||
{
|
||||
if (type.IsByRef)
|
||||
{
|
||||
BuildReferenceTypeSpec(sb, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
BuildSimpleTypeSpec(sb, type);
|
||||
}
|
||||
}
|
||||
|
||||
static void BuildReferenceTypeSpec(StringBuilder sb, Type type)
|
||||
{
|
||||
Fx.Assert(type.HasElementType, "This type must have an element type.");
|
||||
|
||||
BuildSimpleTypeSpec(sb, type.GetElementType());
|
||||
sb.Append('&');
|
||||
}
|
||||
|
||||
static void BuildSimpleTypeSpec(StringBuilder sb, Type type)
|
||||
{
|
||||
if (type.IsPointer)
|
||||
{
|
||||
BuildPointerTypeSpec(sb, type);
|
||||
}
|
||||
else if (type.IsArray)
|
||||
{
|
||||
BuildArrayTypeSpec(sb, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
BuildTypeName(sb, type);
|
||||
}
|
||||
}
|
||||
|
||||
static void BuildPointerTypeSpec(StringBuilder sb, Type type)
|
||||
{
|
||||
Fx.Assert(type.HasElementType, "This type must have an element type.");
|
||||
|
||||
BuildSimpleTypeSpec(sb, type.GetElementType());
|
||||
sb.Append('*');
|
||||
}
|
||||
|
||||
static void BuildArrayTypeSpec(StringBuilder sb, Type type)
|
||||
{
|
||||
Fx.Assert(type.IsArray, "This type must be an array type.");
|
||||
Fx.Assert(type.HasElementType, "This type must have an element type.");
|
||||
|
||||
BuildSimpleTypeSpec(sb, type.GetElementType());
|
||||
|
||||
int arrayRank = type.GetArrayRank();
|
||||
Fx.Assert(arrayRank > 0, "number of dimentions of this array must be greater than 0.");
|
||||
|
||||
sb.Append('[');
|
||||
for (int i = 1; i < arrayRank; i++)
|
||||
{
|
||||
sb.Append(',');
|
||||
}
|
||||
sb.Append(']');
|
||||
}
|
||||
|
||||
static void BuildTypeName(StringBuilder sb, Type type)
|
||||
{
|
||||
BuildNamespaceTypeName(sb, type);
|
||||
sb.Append(", ");
|
||||
BuildAssemblyNameSpec(sb, type);
|
||||
}
|
||||
|
||||
static void BuildNamespaceTypeName(StringBuilder sb, Type type)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(type.Namespace))
|
||||
{
|
||||
sb.Append(type.Namespace);
|
||||
sb.Append('.');
|
||||
}
|
||||
BuildNestedTypeName(sb, type);
|
||||
}
|
||||
|
||||
static void BuildNestedTypeName(StringBuilder sb, Type type)
|
||||
{
|
||||
if (type.IsNested)
|
||||
{
|
||||
BuildNestedTypeName(sb, type.DeclaringType);
|
||||
sb.Append('+');
|
||||
}
|
||||
|
||||
BuildSimpleName(sb, type);
|
||||
}
|
||||
|
||||
static void BuildSimpleName(StringBuilder sb, Type type)
|
||||
{
|
||||
sb.Append(type.Name);
|
||||
|
||||
if (type.IsGenericType && !type.IsGenericTypeDefinition)
|
||||
{
|
||||
sb.Append('[');
|
||||
Type[] genericArguments = type.GetGenericArguments();
|
||||
|
||||
sb.Append('[');
|
||||
BuildTypeSpec(sb, genericArguments[0]);
|
||||
sb.Append(']');
|
||||
|
||||
for (int i = 1; i < genericArguments.Length; i++)
|
||||
{
|
||||
sb.Append(',');
|
||||
sb.Append('[');
|
||||
BuildTypeSpec(sb, genericArguments[i]);
|
||||
sb.Append(']');
|
||||
}
|
||||
|
||||
sb.Append(']');
|
||||
}
|
||||
}
|
||||
|
||||
static void BuildAssemblyNameSpec(StringBuilder sb, Type type)
|
||||
{
|
||||
// only write assembly simple name,
|
||||
// omit version, culture and public token
|
||||
AssemblyName tempAssemName = new AssemblyName(type.Assembly.FullName);
|
||||
sb.Append(tempAssemName.Name);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
// <copyright>
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace System.Activities.DynamicUpdate
|
||||
{
|
||||
using System;
|
||||
using System.Xaml;
|
||||
|
||||
public static class DynamicUpdateInfo
|
||||
{
|
||||
private static AttachableMemberIdentifier mapItemProperty = new AttachableMemberIdentifier(typeof(DynamicUpdateInfo), "MapItem");
|
||||
private static AttachableMemberIdentifier originalDefinitionProperty = new AttachableMemberIdentifier(typeof(DynamicUpdateInfo), "OriginalDefinition");
|
||||
private static AttachableMemberIdentifier originalActivityBuilderProperty = new AttachableMemberIdentifier(typeof(DynamicUpdateInfo), "OriginalActivityBuilder");
|
||||
|
||||
public static void SetMapItem(object instance, DynamicUpdateMapItem mapItem)
|
||||
{
|
||||
if (mapItem != null)
|
||||
{
|
||||
AttachablePropertyServices.SetProperty(instance, mapItemProperty, mapItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
AttachablePropertyServices.RemoveProperty(instance, mapItemProperty);
|
||||
}
|
||||
}
|
||||
|
||||
public static DynamicUpdateMapItem GetMapItem(object instance)
|
||||
{
|
||||
DynamicUpdateMapItem result;
|
||||
if (AttachablePropertyServices.TryGetProperty(instance, mapItemProperty, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetOriginalDefinition(object instance, Activity originalDefinition)
|
||||
{
|
||||
if (originalDefinition != null)
|
||||
{
|
||||
AttachablePropertyServices.SetProperty(instance, originalDefinitionProperty, originalDefinition);
|
||||
}
|
||||
else
|
||||
{
|
||||
AttachablePropertyServices.RemoveProperty(instance, originalDefinitionProperty);
|
||||
}
|
||||
}
|
||||
|
||||
public static Activity GetOriginalDefinition(object instance)
|
||||
{
|
||||
Activity result;
|
||||
if (AttachablePropertyServices.TryGetProperty(instance, originalDefinitionProperty, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetOriginalActivityBuilder(object instance, ActivityBuilder originalActivityBuilder)
|
||||
{
|
||||
if (originalActivityBuilder != null)
|
||||
{
|
||||
AttachablePropertyServices.SetProperty(instance, originalActivityBuilderProperty, originalActivityBuilder);
|
||||
}
|
||||
else
|
||||
{
|
||||
AttachablePropertyServices.RemoveProperty(instance, originalActivityBuilderProperty);
|
||||
}
|
||||
}
|
||||
|
||||
public static ActivityBuilder GetOriginalActivityBuilder(object instance)
|
||||
{
|
||||
ActivityBuilder result;
|
||||
if (AttachablePropertyServices.TryGetProperty(instance, originalActivityBuilderProperty, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,261 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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<string, object> 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<string, object> Merge(IDictionary<string, object> first, IDictionary<string, object> second)
|
||||
{
|
||||
if (first == null || second == null)
|
||||
{
|
||||
return first ?? second;
|
||||
}
|
||||
|
||||
Dictionary<string, object> result = new Dictionary<string, object>(first);
|
||||
foreach (KeyValuePair<string, object> 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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
// <copyright>
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace System.Activities.DynamicUpdate
|
||||
{
|
||||
using System;
|
||||
using System.Activities.XamlIntegration;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
[TypeConverter(typeof(DynamicUpdateMapItemConverter))]
|
||||
[DataContract]
|
||||
public class DynamicUpdateMapItem
|
||||
{
|
||||
internal DynamicUpdateMapItem(int originalId)
|
||||
{
|
||||
this.OriginalId = originalId;
|
||||
}
|
||||
|
||||
internal DynamicUpdateMapItem(int originalVariableOwnerId, int originalVariableId)
|
||||
{
|
||||
this.OriginalVariableOwnerId = originalVariableOwnerId;
|
||||
this.OriginalId = originalVariableId;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
internal int OriginalId
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
internal int OriginalVariableOwnerId
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
internal bool IsVariableMapItem
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.OriginalVariableOwnerId > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,277 @@
|
||||
// <copyright>
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace System.Activities.DynamicUpdate
|
||||
{
|
||||
using System;
|
||||
using System.Activities.DynamicUpdate;
|
||||
using System.Activities.XamlIntegration;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Runtime;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
public class DynamicUpdateMapQuery
|
||||
{
|
||||
private DynamicUpdateMap map;
|
||||
private Activity updatedWorkflowDefinition;
|
||||
private Activity originalWorkflowDefinition;
|
||||
|
||||
internal DynamicUpdateMapQuery(DynamicUpdateMap map, Activity updatedWorkflowDefinition, Activity originalWorkflowDefinition)
|
||||
{
|
||||
Fx.Assert(updatedWorkflowDefinition == updatedWorkflowDefinition.RootActivity, "This parameter must be root of workflow");
|
||||
Fx.Assert(originalWorkflowDefinition == originalWorkflowDefinition.RootActivity, "This parameter must be root of workflow");
|
||||
|
||||
this.map = map;
|
||||
this.updatedWorkflowDefinition = updatedWorkflowDefinition;
|
||||
this.originalWorkflowDefinition = originalWorkflowDefinition;
|
||||
}
|
||||
|
||||
public Activity FindMatch(Activity activity)
|
||||
{
|
||||
if (activity == null)
|
||||
{
|
||||
throw FxTrace.Exception.ArgumentNull("activity");
|
||||
}
|
||||
|
||||
if (IsInNewDefinition(activity))
|
||||
{
|
||||
return this.MatchNewToOld(activity);
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.MatchOldToNew(activity);
|
||||
}
|
||||
}
|
||||
|
||||
public Variable FindMatch(Variable variable)
|
||||
{
|
||||
if (variable == null)
|
||||
{
|
||||
throw FxTrace.Exception.ArgumentNull("variable");
|
||||
}
|
||||
|
||||
if (IsInNewDefinition(variable))
|
||||
{
|
||||
return this.MatchNewToOld(variable);
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.MatchOldToNew(variable);
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanApplyUpdateWhileRunning(Activity activity)
|
||||
{
|
||||
if (activity == null)
|
||||
{
|
||||
throw FxTrace.Exception.ArgumentNull("activity");
|
||||
}
|
||||
|
||||
return this.CanApplyUpdateWhileRunning(activity, IsInNewDefinition(activity));
|
||||
}
|
||||
|
||||
private Activity MatchNewToOld(Activity newActivity)
|
||||
{
|
||||
DynamicUpdateMapEntry entry;
|
||||
return this.MatchNewToOld(newActivity, out entry);
|
||||
}
|
||||
|
||||
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 Variable MatchNewToOld(Variable newVariable)
|
||||
{
|
||||
if (!newVariable.IsPublic)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
DynamicUpdateMapEntry entry;
|
||||
Activity oldOwner = this.MatchNewToOld(newVariable.Owner, out entry);
|
||||
if (oldOwner == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int newIndex = newVariable.Owner.RuntimeVariables.IndexOf(newVariable);
|
||||
int? oldIndex = entry.HasEnvironmentUpdates ?
|
||||
entry.EnvironmentUpdateMap.GetOldVariableIndex(newIndex) :
|
||||
newIndex;
|
||||
|
||||
return oldIndex.HasValue ? oldOwner.RuntimeVariables[oldIndex.Value] : null;
|
||||
}
|
||||
|
||||
private Activity MatchOldToNew(Activity oldActivity)
|
||||
{
|
||||
DynamicUpdateMapEntry entry;
|
||||
return this.MatchOldToNew(oldActivity, out entry);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private Variable MatchOldToNew(Variable oldVariable)
|
||||
{
|
||||
if (!oldVariable.IsPublic)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
DynamicUpdateMapEntry entry;
|
||||
Activity newOwner = this.MatchOldToNew(oldVariable.Owner, out entry);
|
||||
if (newOwner == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int oldIndex = oldVariable.Owner.RuntimeVariables.IndexOf(oldVariable);
|
||||
int? newIndex = entry.HasEnvironmentUpdates ?
|
||||
entry.EnvironmentUpdateMap.GetNewVariableIndex(oldIndex) :
|
||||
oldIndex;
|
||||
|
||||
return newIndex.HasValue ? newOwner.RuntimeVariables[newIndex.Value] : null;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private bool IsInNewDefinition(Activity activity, bool isVariableOwner = false)
|
||||
{
|
||||
bool result = false;
|
||||
if (activity.RootActivity == this.updatedWorkflowDefinition)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
else if (activity.RootActivity == this.originalWorkflowDefinition)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowNotInDefinition(isVariableOwner,
|
||||
SR.QueryVariableIsNotInDefinition,
|
||||
SR.QueryActivityIsNotInDefinition);
|
||||
}
|
||||
|
||||
// We only support either the public or the implementation IdSpace at the root of the workflow.
|
||||
// The user does not have visibility into nested IdSpaces so should not be querying into them.
|
||||
if (this.map.IsForImplementation)
|
||||
{
|
||||
if (activity.MemberOf.Owner != activity.RootActivity)
|
||||
{
|
||||
ThrowNotInDefinition(isVariableOwner,
|
||||
SR.QueryVariableIsPublic(activity.RootActivity),
|
||||
SR.QueryActivityIsPublic(activity.RootActivity));
|
||||
}
|
||||
}
|
||||
else if (activity.MemberOf != activity.RootActivity.MemberOf)
|
||||
{
|
||||
ThrowNotInDefinition(isVariableOwner,
|
||||
SR.QueryVariableIsInImplementation(activity.MemberOf.Owner),
|
||||
SR.QueryActivityIsInImplementation(activity.MemberOf.Owner));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool IsInNewDefinition(Variable variable)
|
||||
{
|
||||
if (variable.Owner == null)
|
||||
{
|
||||
throw FxTrace.Exception.Argument("variable", SR.QueryVariableIsNotInDefinition);
|
||||
}
|
||||
if (!variable.IsPublic)
|
||||
{
|
||||
throw FxTrace.Exception.Argument("variable", SR.QueryVariableIsNotPublic);
|
||||
}
|
||||
return IsInNewDefinition(variable.Owner, true);
|
||||
}
|
||||
|
||||
private void ThrowNotInDefinition(bool isVariableOwner, string variableMessage, string activityMessage)
|
||||
{
|
||||
if (isVariableOwner)
|
||||
{
|
||||
throw FxTrace.Exception.Argument("variable", variableMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw FxTrace.Exception.Argument("activity", activityMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,270 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace System.Activities.DynamicUpdate
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Activities;
|
||||
using System.Activities.Expressions;
|
||||
using System.Activities.DynamicUpdate;
|
||||
using System.Activities.Hosting;
|
||||
using System.Activities.Runtime;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Runtime;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Xaml;
|
||||
using System.Activities.Validation;
|
||||
using Microsoft.VisualBasic.Activities;
|
||||
|
||||
public static class DynamicUpdateServices
|
||||
{
|
||||
private static Func<Activity, Exception> onInvalidActivityToBlockUpdate =
|
||||
new Func<Activity, Exception>(OnInvalidActivityToBlockUpdate);
|
||||
|
||||
private static Func<Activity, Exception> onInvalidImplementationMapAssociation =
|
||||
new Func<Activity, Exception>(OnInvalidImplementationMapAssociation);
|
||||
|
||||
private static AttachableMemberIdentifier implementationMapProperty = new AttachableMemberIdentifier(typeof(DynamicUpdateServices), "ImplementationMap");
|
||||
|
||||
public static void PrepareForUpdate(Activity workflowDefinitionToBeUpdated)
|
||||
{
|
||||
if (workflowDefinitionToBeUpdated == null)
|
||||
{
|
||||
throw FxTrace.Exception.ArgumentNull("workflowDefinitionToBeUpdated");
|
||||
}
|
||||
|
||||
InternalPrepareForUpdate(workflowDefinitionToBeUpdated, false);
|
||||
}
|
||||
|
||||
public static void PrepareForUpdate(ActivityBuilder activityDefinitionToBeUpdated)
|
||||
{
|
||||
if (activityDefinitionToBeUpdated == null)
|
||||
{
|
||||
throw FxTrace.Exception.ArgumentNull("activityDefinitionToBeUpdated");
|
||||
}
|
||||
|
||||
InternalPrepareForUpdate(activityDefinitionToBeUpdated, true);
|
||||
}
|
||||
|
||||
private static void InternalPrepareForUpdate(object definitionToBeUpdated, bool forImplementation)
|
||||
{
|
||||
// Clone the definition
|
||||
object clone;
|
||||
using (XamlObjectReader reader = new XamlObjectReader(definitionToBeUpdated))
|
||||
{
|
||||
using (XamlObjectWriter writer = new XamlObjectWriter(reader.SchemaContext))
|
||||
{
|
||||
XamlServices.Transform(reader, writer);
|
||||
clone = writer.Result;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the match info
|
||||
// Set the match info as attached properties so it is serializable,
|
||||
// and available when the user calls CreateUpdateMap
|
||||
|
||||
IDictionary<object, DynamicUpdateMapItem> mapItems;
|
||||
if (!forImplementation)
|
||||
{
|
||||
DynamicUpdateInfo.SetOriginalDefinition(definitionToBeUpdated, (Activity)clone);
|
||||
mapItems = DynamicUpdateMap.CalculateMapItems((Activity)definitionToBeUpdated);
|
||||
}
|
||||
else
|
||||
{
|
||||
DynamicUpdateInfo.SetOriginalActivityBuilder(definitionToBeUpdated, (ActivityBuilder)clone);
|
||||
mapItems = DynamicUpdateMap.CalculateImplementationMapItems(GetDynamicActivity((ActivityBuilder)definitionToBeUpdated));
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<object, DynamicUpdateMapItem> objectInfo in mapItems)
|
||||
{
|
||||
DynamicUpdateInfo.SetMapItem(objectInfo.Key, objectInfo.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public static DynamicUpdateMap CreateUpdateMap(Activity updatedWorkflowDefinition)
|
||||
{
|
||||
return CreateUpdateMap(updatedWorkflowDefinition, null);
|
||||
}
|
||||
|
||||
public static DynamicUpdateMap CreateUpdateMap(Activity updatedWorkflowDefinition, IEnumerable<Activity> disallowUpdateInsideActivities)
|
||||
{
|
||||
IList<ActivityBlockingUpdate> activitiesBlockingUpdate;
|
||||
return CreateUpdateMap(updatedWorkflowDefinition, disallowUpdateInsideActivities, out activitiesBlockingUpdate);
|
||||
}
|
||||
|
||||
[SuppressMessage(FxCop.Category.Design, FxCop.Rule.AvoidOutParameters, Justification = "Approved Design. Need to return the map and the block list.")]
|
||||
public static DynamicUpdateMap CreateUpdateMap(Activity updatedWorkflowDefinition, IEnumerable<Activity> disallowUpdateInsideActivities, out IList<ActivityBlockingUpdate> activitiesBlockingUpdate)
|
||||
{
|
||||
if (updatedWorkflowDefinition == null)
|
||||
{
|
||||
throw FxTrace.Exception.ArgumentNull("updatedWorkflowDefinition");
|
||||
}
|
||||
|
||||
Activity originalDefinition = DynamicUpdateInfo.GetOriginalDefinition(updatedWorkflowDefinition);
|
||||
if (originalDefinition == null)
|
||||
{
|
||||
throw FxTrace.Exception.Argument("updatedWorkflowDefinition", SR.MustCallPrepareBeforeFinalize);
|
||||
}
|
||||
|
||||
DynamicUpdateMap result = InternalTryCreateUpdateMap(updatedWorkflowDefinition, originalDefinition, disallowUpdateInsideActivities, false, out activitiesBlockingUpdate);
|
||||
// Remove the DynamicUpdateMapItems now that the update is finalized
|
||||
// Calling CalculateMapItems is actually an unnecessary perf hit since it calls CacheMetadata
|
||||
// again; but we do it so that Finalize is implemented purely in terms of other public APIs.
|
||||
DynamicUpdateInfo.SetOriginalDefinition(updatedWorkflowDefinition, null);
|
||||
IDictionary<object, DynamicUpdateMapItem> mapItems = DynamicUpdateMap.CalculateMapItems(updatedWorkflowDefinition);
|
||||
foreach (object matchObject in mapItems.Keys)
|
||||
{
|
||||
DynamicUpdateInfo.SetMapItem(matchObject, null);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static DynamicUpdateMap CreateUpdateMap(ActivityBuilder updatedActivityDefinition)
|
||||
{
|
||||
return CreateUpdateMap(updatedActivityDefinition, null);
|
||||
}
|
||||
|
||||
public static DynamicUpdateMap CreateUpdateMap(ActivityBuilder updatedActivityDefinition, IEnumerable<Activity> disallowUpdateInsideActivities)
|
||||
{
|
||||
IList<ActivityBlockingUpdate> activitiesBlockingUpdate;
|
||||
return CreateUpdateMap(updatedActivityDefinition, disallowUpdateInsideActivities, out activitiesBlockingUpdate);
|
||||
}
|
||||
|
||||
[SuppressMessage(FxCop.Category.Design, FxCop.Rule.AvoidOutParameters, Justification = "Approved Design. Need to return the map and the block list.")]
|
||||
public static DynamicUpdateMap CreateUpdateMap(ActivityBuilder updatedActivityDefinition, IEnumerable<Activity> disallowUpdateInsideActivities, out IList<ActivityBlockingUpdate> activitiesBlockingUpdate)
|
||||
{
|
||||
if (updatedActivityDefinition == null)
|
||||
{
|
||||
throw FxTrace.Exception.ArgumentNull("updatedActivityDefinition");
|
||||
}
|
||||
|
||||
ActivityBuilder originalActivityDefinition = DynamicUpdateInfo.GetOriginalActivityBuilder(updatedActivityDefinition);
|
||||
if (originalActivityDefinition == null)
|
||||
{
|
||||
throw FxTrace.Exception.Argument("updatedActivityDefinition", SR.MustCallPrepareBeforeFinalize);
|
||||
}
|
||||
|
||||
Activity originalBuiltRoot = GetDynamicActivity(originalActivityDefinition);
|
||||
Activity updatedBuiltRoot = GetDynamicActivity(updatedActivityDefinition);
|
||||
|
||||
DynamicUpdateMap result = InternalTryCreateUpdateMap(updatedBuiltRoot, originalBuiltRoot, disallowUpdateInsideActivities, true, out activitiesBlockingUpdate);
|
||||
// Remove the DynamicUpdateMapItems now that the update is finalized
|
||||
// Calling CalculateMapItems is actually an unnecessary perf hit since it calls CacheMetadata
|
||||
// again; but we do it so that Finalize is implemented purely in terms of other public APIs.
|
||||
DynamicUpdateInfo.SetOriginalActivityBuilder(updatedActivityDefinition, null);
|
||||
IDictionary<object, DynamicUpdateMapItem> mapItems = DynamicUpdateMap.CalculateImplementationMapItems(updatedBuiltRoot);
|
||||
foreach (object matchObject in mapItems.Keys)
|
||||
{
|
||||
DynamicUpdateInfo.SetMapItem(matchObject, null);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static DynamicUpdateMap InternalTryCreateUpdateMap(Activity updatedDefinition, Activity originalDefinition, IEnumerable<Activity> disallowUpdateInsideActivities, bool forImplementation, out IList<ActivityBlockingUpdate> activitiesBlockingUpdate)
|
||||
{
|
||||
DynamicUpdateMapBuilder builder = new DynamicUpdateMapBuilder
|
||||
{
|
||||
ForImplementation = forImplementation,
|
||||
LookupMapItem = DynamicUpdateInfo.GetMapItem,
|
||||
LookupImplementationMap = GetImplementationMap,
|
||||
UpdatedWorkflowDefinition = updatedDefinition,
|
||||
OriginalWorkflowDefinition = originalDefinition,
|
||||
OnInvalidActivityToBlockUpdate = onInvalidActivityToBlockUpdate,
|
||||
OnInvalidImplementationMapAssociation = onInvalidImplementationMapAssociation,
|
||||
};
|
||||
if (disallowUpdateInsideActivities != null)
|
||||
{
|
||||
foreach (Activity activity in disallowUpdateInsideActivities)
|
||||
{
|
||||
builder.DisallowUpdateInside.Add(activity);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.CreateMap(out activitiesBlockingUpdate);
|
||||
}
|
||||
|
||||
public static DynamicUpdateMap GetImplementationMap(Activity targetActivity)
|
||||
{
|
||||
DynamicUpdateMap result;
|
||||
if (AttachablePropertyServices.TryGetProperty(targetActivity, implementationMapProperty, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetImplementationMap(Activity targetActivity, DynamicUpdateMap implementationMap)
|
||||
{
|
||||
if (implementationMap != null)
|
||||
{
|
||||
AttachablePropertyServices.SetProperty(targetActivity, implementationMapProperty, implementationMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
AttachablePropertyServices.RemoveProperty(targetActivity, implementationMapProperty);
|
||||
}
|
||||
}
|
||||
|
||||
static DynamicActivity GetDynamicActivity(ActivityBuilder activityDefinition)
|
||||
{
|
||||
DynamicActivity result = new DynamicActivity
|
||||
{
|
||||
Name = activityDefinition.Name
|
||||
};
|
||||
foreach (DynamicActivityProperty property in activityDefinition.Properties)
|
||||
{
|
||||
result.Properties.Add(property);
|
||||
}
|
||||
foreach (Attribute attrib in activityDefinition.Attributes)
|
||||
{
|
||||
result.Attributes.Add(attrib);
|
||||
}
|
||||
foreach (Constraint constraint in activityDefinition.Constraints)
|
||||
{
|
||||
result.Constraints.Add(constraint);
|
||||
}
|
||||
result.Implementation = () => activityDefinition.Implementation;
|
||||
|
||||
VisualBasicSettings vbsettings = VisualBasic.GetSettings(activityDefinition);
|
||||
if (vbsettings != null)
|
||||
{
|
||||
VisualBasic.SetSettings(result, vbsettings);
|
||||
}
|
||||
|
||||
IList<string> namespacesForImplementation = TextExpression.GetNamespacesForImplementation(activityDefinition);
|
||||
if (namespacesForImplementation.Count > 0)
|
||||
{
|
||||
TextExpression.SetNamespacesForImplementation(result, namespacesForImplementation);
|
||||
}
|
||||
|
||||
IList<AssemblyReference> referencesForImplementation = TextExpression.GetReferencesForImplementation(activityDefinition);
|
||||
if (referencesForImplementation.Count > 0)
|
||||
{
|
||||
TextExpression.SetReferencesForImplementation(result, referencesForImplementation);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static Exception OnInvalidActivityToBlockUpdate(Activity activity)
|
||||
{
|
||||
return new ArgumentException(SR.InvalidActivityToBlockUpdateServices(activity), "disallowUpdateInsideActivities");
|
||||
}
|
||||
|
||||
static Exception OnInvalidImplementationMapAssociation(Activity activity)
|
||||
{
|
||||
return new InvalidOperationException(SR.InvalidImplementationMapAssociationServices(activity));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,299 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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]
|
||||
internal class EnvironmentUpdateMap
|
||||
{
|
||||
IList<EnvironmentUpdateMapEntry> variableEntries;
|
||||
IList<EnvironmentUpdateMapEntry> privateVariableEntries;
|
||||
IList<EnvironmentUpdateMapEntry> argumentEntries;
|
||||
|
||||
public EnvironmentUpdateMap()
|
||||
{
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
public int NewArgumentCount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
public int OldArgumentCount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
public int NewVariableCount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
public int OldVariableCount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
public int NewPrivateVariableCount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
public int OldPrivateVariableCount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
public int RuntimeDelegateArgumentCount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false, Name = "variableEntries")]
|
||||
internal IList<EnvironmentUpdateMapEntry> SerializedVariableEntries
|
||||
{
|
||||
get { return this.variableEntries; }
|
||||
set { this.variableEntries = value; }
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false, Name = "privateVariableEntries")]
|
||||
internal IList<EnvironmentUpdateMapEntry> SerializedPrivateVariableEntries
|
||||
{
|
||||
get { return this.privateVariableEntries; }
|
||||
set { this.privateVariableEntries = value; }
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false, Name = "argumentEntries")]
|
||||
internal IList<EnvironmentUpdateMapEntry> SerializedArgumentEntries
|
||||
{
|
||||
get { return this.argumentEntries; }
|
||||
set { this.argumentEntries = value; }
|
||||
}
|
||||
|
||||
internal bool IsAdditionToNoSymbols
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.OldArgumentCount + this.OldVariableCount + this.OldPrivateVariableCount + this.RuntimeDelegateArgumentCount) == 0 &&
|
||||
(this.NewArgumentCount + this.NewVariableCount + this.NewPrivateVariableCount + this.RuntimeDelegateArgumentCount) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool HasVariableEntries
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.variableEntries != null && this.variableEntries.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool HasPrivateVariableEntries
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.privateVariableEntries != null && this.privateVariableEntries.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool HasArgumentEntries
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.argumentEntries != null && this.argumentEntries.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public IList<EnvironmentUpdateMapEntry> VariableEntries
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.variableEntries == null)
|
||||
{
|
||||
this.variableEntries = new List<EnvironmentUpdateMapEntry>();
|
||||
}
|
||||
|
||||
return this.variableEntries;
|
||||
}
|
||||
}
|
||||
|
||||
public IList<EnvironmentUpdateMapEntry> PrivateVariableEntries
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.privateVariableEntries == null)
|
||||
{
|
||||
this.privateVariableEntries = new List<EnvironmentUpdateMapEntry>();
|
||||
}
|
||||
|
||||
return this.privateVariableEntries;
|
||||
}
|
||||
}
|
||||
|
||||
public IList<EnvironmentUpdateMapEntry> ArgumentEntries
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.argumentEntries == null)
|
||||
{
|
||||
this.argumentEntries = new List<EnvironmentUpdateMapEntry>();
|
||||
}
|
||||
|
||||
return this.argumentEntries;
|
||||
}
|
||||
}
|
||||
|
||||
internal static EnvironmentUpdateMap Merge(EnvironmentUpdateMap first, EnvironmentUpdateMap second,
|
||||
DynamicUpdateMap.MergeErrorContext errorContext)
|
||||
{
|
||||
if (first == null || second == null)
|
||||
{
|
||||
return first ?? second;
|
||||
}
|
||||
|
||||
ThrowIfMapsIncompatible(first, second, errorContext);
|
||||
|
||||
EnvironmentUpdateMap result = new EnvironmentUpdateMap
|
||||
{
|
||||
OldArgumentCount = first.OldArgumentCount,
|
||||
NewArgumentCount = second.NewArgumentCount,
|
||||
OldVariableCount = first.OldVariableCount,
|
||||
NewVariableCount = second.NewVariableCount,
|
||||
OldPrivateVariableCount = first.OldPrivateVariableCount,
|
||||
NewPrivateVariableCount = second.NewPrivateVariableCount,
|
||||
};
|
||||
|
||||
result.variableEntries = Merge(result.NewVariableCount, first.VariableEntries, second.VariableEntries);
|
||||
result.privateVariableEntries = Merge(result.NewPrivateVariableCount, first.PrivateVariableEntries, second.PrivateVariableEntries);
|
||||
result.argumentEntries = Merge(result.NewArgumentCount, first.ArgumentEntries, second.ArgumentEntries);
|
||||
|
||||
if (result.OldArgumentCount != result.NewArgumentCount ||
|
||||
result.OldVariableCount != result.NewVariableCount ||
|
||||
result.OldPrivateVariableCount != result.NewPrivateVariableCount ||
|
||||
result.HasArgumentEntries || result.HasVariableEntries || result.HasPrivateVariableEntries)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal int? GetOldVariableIndex(int newIndex)
|
||||
{
|
||||
EnvironmentUpdateMapEntry environmentEntry = FindByNewIndex(this.VariableEntries, newIndex);
|
||||
if (environmentEntry != null)
|
||||
{
|
||||
return environmentEntry.IsAddition ? (int?)null : environmentEntry.OldOffset;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal int? GetNewVariableIndex(int oldIndex)
|
||||
{
|
||||
foreach (EnvironmentUpdateMapEntry environmentEntry in this.VariableEntries)
|
||||
{
|
||||
if (environmentEntry.OldOffset == oldIndex)
|
||||
{
|
||||
return environmentEntry.NewOffset;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal int? GetNewPrivateVariableIndex(int oldIndex)
|
||||
{
|
||||
foreach (EnvironmentUpdateMapEntry environmentEntry in this.PrivateVariableEntries)
|
||||
{
|
||||
if (environmentEntry.OldOffset == oldIndex)
|
||||
{
|
||||
return environmentEntry.NewOffset;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static void ThrowIfMapsIncompatible(EnvironmentUpdateMap first, EnvironmentUpdateMap second,
|
||||
DynamicUpdateMap.MergeErrorContext errorContext)
|
||||
{
|
||||
if (first.NewArgumentCount != second.OldArgumentCount ||
|
||||
first.NewVariableCount != second.OldVariableCount ||
|
||||
first.NewPrivateVariableCount != second.OldPrivateVariableCount)
|
||||
{
|
||||
errorContext.Throw(SR.InvalidMergeMapEnvironmentCount(
|
||||
first.NewArgumentCount, first.NewVariableCount, first.NewPrivateVariableCount,
|
||||
second.OldArgumentCount, second.OldVariableCount, second.OldPrivateVariableCount));
|
||||
}
|
||||
}
|
||||
|
||||
static IList<EnvironmentUpdateMapEntry> Merge(int finalCount, IList<EnvironmentUpdateMapEntry> first,
|
||||
IList<EnvironmentUpdateMapEntry> second)
|
||||
{
|
||||
List<EnvironmentUpdateMapEntry> result = new List<EnvironmentUpdateMapEntry>();
|
||||
for (int i = 0; i < finalCount; i++)
|
||||
{
|
||||
EnvironmentUpdateMapEntry resultEntry = MergeEntry(i, first, second);
|
||||
if (resultEntry != null)
|
||||
{
|
||||
result.Add(resultEntry);
|
||||
}
|
||||
}
|
||||
|
||||
return result.Count > 0 ? result : null;
|
||||
}
|
||||
|
||||
static EnvironmentUpdateMapEntry MergeEntry(int finalIndex, IList<EnvironmentUpdateMapEntry> first,
|
||||
IList<EnvironmentUpdateMapEntry> second)
|
||||
{
|
||||
EnvironmentUpdateMapEntry secondEntry = FindByNewIndex(second, finalIndex);
|
||||
EnvironmentUpdateMapEntry firstEntry;
|
||||
if (secondEntry != null)
|
||||
{
|
||||
firstEntry = secondEntry.IsAddition ? null : FindByNewIndex(first, secondEntry.OldOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
firstEntry = FindByNewIndex(first, finalIndex);
|
||||
}
|
||||
|
||||
return EnvironmentUpdateMapEntry.Merge(firstEntry, secondEntry);
|
||||
}
|
||||
|
||||
static EnvironmentUpdateMapEntry FindByNewIndex(IList<EnvironmentUpdateMapEntry> entries, int newIndex)
|
||||
{
|
||||
foreach (EnvironmentUpdateMapEntry environmentEntry in entries)
|
||||
{
|
||||
if (environmentEntry.NewOffset == newIndex)
|
||||
{
|
||||
return environmentEntry;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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]
|
||||
internal class EnvironmentUpdateMapEntry
|
||||
{
|
||||
internal const int NonExistent = -1;
|
||||
|
||||
public EnvironmentUpdateMapEntry()
|
||||
{
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
public int OldOffset
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
public int NewOffset
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
public bool IsNewHandle
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
internal bool IsAddition
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.OldOffset == EnvironmentUpdateMapEntry.NonExistent;
|
||||
}
|
||||
}
|
||||
|
||||
internal static EnvironmentUpdateMapEntry Merge(EnvironmentUpdateMapEntry first, EnvironmentUpdateMapEntry second)
|
||||
{
|
||||
if (first == null || second == null)
|
||||
{
|
||||
return first ?? second;
|
||||
}
|
||||
|
||||
Fx.Assert(first.NewOffset == second.OldOffset && !second.IsAddition, "Merging mismatched entries");
|
||||
if (first.OldOffset == second.NewOffset)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new EnvironmentUpdateMapEntry
|
||||
{
|
||||
OldOffset = first.OldOffset,
|
||||
NewOffset = second.NewOffset,
|
||||
IsNewHandle = first.IsNewHandle
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
// <copyright>
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace System.Activities.DynamicUpdate
|
||||
{
|
||||
internal interface IInstanceUpdatable
|
||||
{
|
||||
void InternalUpdateInstance(NativeActivityUpdateContext updateContext);
|
||||
}
|
||||
}
|
@@ -0,0 +1,116 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace System.Activities.DynamicUpdate
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Security;
|
||||
using System.Runtime;
|
||||
|
||||
[Serializable]
|
||||
public class InstanceUpdateException : Exception
|
||||
{
|
||||
private ReadOnlyCollection<ActivityBlockingUpdate> blockingActivities;
|
||||
|
||||
public InstanceUpdateException()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
public InstanceUpdateException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public InstanceUpdateException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
public InstanceUpdateException(IList<ActivityBlockingUpdate> blockingActivities)
|
||||
: this(BuildMessage(blockingActivities), blockingActivities)
|
||||
{
|
||||
}
|
||||
|
||||
public InstanceUpdateException(string message, IList<ActivityBlockingUpdate> blockingActivities)
|
||||
: base(message)
|
||||
{
|
||||
if (blockingActivities != null)
|
||||
{
|
||||
this.blockingActivities = new ReadOnlyCollection<ActivityBlockingUpdate>(blockingActivities);
|
||||
}
|
||||
}
|
||||
|
||||
public InstanceUpdateException(string message, IList<ActivityBlockingUpdate> blockingActivities, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
if (blockingActivities != null)
|
||||
{
|
||||
this.blockingActivities = new ReadOnlyCollection<ActivityBlockingUpdate>(blockingActivities);
|
||||
}
|
||||
}
|
||||
|
||||
protected InstanceUpdateException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{
|
||||
this.blockingActivities = (ReadOnlyCollection<ActivityBlockingUpdate>)info.GetValue(
|
||||
"blockingActivities", typeof(ReadOnlyCollection<ActivityBlockingUpdate>));
|
||||
}
|
||||
|
||||
public IList<ActivityBlockingUpdate> BlockingActivities
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.blockingActivities == null)
|
||||
{
|
||||
this.blockingActivities = new ReadOnlyCollection<ActivityBlockingUpdate>(new ActivityBlockingUpdate[0]);
|
||||
}
|
||||
|
||||
return this.blockingActivities;
|
||||
}
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Critical because we are overriding a critical method in the base class.")]
|
||||
[SecurityCritical]
|
||||
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
base.GetObjectData(info, context);
|
||||
info.AddValue("blockingActivities", this.blockingActivities);
|
||||
}
|
||||
|
||||
private static string BuildMessage(IList<ActivityBlockingUpdate> blockingActivities)
|
||||
{
|
||||
if (blockingActivities != null && blockingActivities.Count > 0)
|
||||
{
|
||||
StringBuilder errorMsgs = new StringBuilder();
|
||||
for (int i = 0; i < blockingActivities.Count - 1; i++)
|
||||
{
|
||||
errorMsgs.AppendLine(GetMessage(blockingActivities[i]));
|
||||
}
|
||||
|
||||
errorMsgs.Append(GetMessage(blockingActivities[blockingActivities.Count - 1]));
|
||||
return errorMsgs.ToString();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string GetMessage(ActivityBlockingUpdate blockingActivity)
|
||||
{
|
||||
object activity = (object)blockingActivity.Activity ?? blockingActivity.UpdatedActivityId;
|
||||
if (activity != null)
|
||||
{
|
||||
return SR.ActivityBlockingUpdate(activity, blockingActivity.Reason);
|
||||
}
|
||||
else
|
||||
{
|
||||
return blockingActivity.Reason;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,89 @@
|
||||
// <copyright>
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace System.Activities.DynamicUpdate
|
||||
{
|
||||
using System;
|
||||
using System.Activities.Validation;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class NativeActivityUpdateMapMetadata : UpdateMapMetadata
|
||||
{
|
||||
internal NativeActivityUpdateMapMetadata(DynamicUpdateMapBuilder.Finalizer finalizer,
|
||||
DynamicUpdateMapBuilder.IDefinitionMatcher matcher, Activity targetActivity)
|
||||
: base(finalizer, matcher, targetActivity)
|
||||
{
|
||||
}
|
||||
|
||||
public void SaveOriginalValue(Activity updatedChildActivity, object originalValue)
|
||||
{
|
||||
this.ThrowIfDisposed();
|
||||
bool isReferencedChild;
|
||||
ValidateOriginalValueAccess(this.TargetActivity, updatedChildActivity, "updatedChildActivity", out isReferencedChild);
|
||||
if (GetMatch(updatedChildActivity) == null)
|
||||
{
|
||||
throw FxTrace.Exception.Argument("updatedChildActivity", SR.CannotSaveOriginalValueForNewActivity(updatedChildActivity));
|
||||
}
|
||||
|
||||
this.Finalizer.SetOriginalValue(updatedChildActivity, originalValue, isReferencedChild);
|
||||
}
|
||||
|
||||
public void SaveOriginalValue(string propertyName, object originalValue)
|
||||
{
|
||||
this.ThrowIfDisposed();
|
||||
if (propertyName == null)
|
||||
{
|
||||
throw FxTrace.Exception.ArgumentNull("propertyName");
|
||||
}
|
||||
|
||||
if (this.Finalizer.SavedOriginalValuesForCurrentActivity == null)
|
||||
{
|
||||
this.Finalizer.SavedOriginalValuesForCurrentActivity = new Dictionary<string, object>();
|
||||
}
|
||||
this.Finalizer.SavedOriginalValuesForCurrentActivity[propertyName] = originalValue;
|
||||
}
|
||||
|
||||
internal static void ValidateOriginalValueAccess(Activity parent, Activity child, string paramName, out bool isReferencedChild)
|
||||
{
|
||||
if (child == null)
|
||||
{
|
||||
throw FxTrace.Exception.ArgumentNull(paramName);
|
||||
}
|
||||
|
||||
if (!IsPublicOrImportedDelegateOrChild(parent, child, out isReferencedChild))
|
||||
{
|
||||
throw FxTrace.Exception.Argument(paramName, SR.CannotSaveOriginalValueForActivity);
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsPublicOrImportedDelegateOrChild(Activity parent, Activity child, out bool isReferencedChild)
|
||||
{
|
||||
isReferencedChild = false;
|
||||
if (child.Parent == parent)
|
||||
{
|
||||
if (child.HandlerOf == null)
|
||||
{
|
||||
return child.RelationshipToParent == Activity.RelationshipType.Child ||
|
||||
child.RelationshipToParent == Activity.RelationshipType.ImportedChild;
|
||||
}
|
||||
else
|
||||
{
|
||||
return child.HandlerOf.ParentCollectionType == ActivityCollectionType.Public ||
|
||||
child.HandlerOf.ParentCollectionType == ActivityCollectionType.Imports;
|
||||
}
|
||||
}
|
||||
else if (parent.MemberOf != child.MemberOf)
|
||||
{
|
||||
isReferencedChild = true;
|
||||
bool isImport;
|
||||
return IsChild(parent, child, out isImport);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
// <copyright>
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace System.Activities.DynamicUpdate
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime;
|
||||
using System.Text;
|
||||
|
||||
enum UpdateBlockedReason
|
||||
{
|
||||
NotBlocked = 0,
|
||||
Custom = 1,
|
||||
TypeChange,
|
||||
PublicChildrenChange,
|
||||
InvalidImplementationMap,
|
||||
PrivateMembersHaveChanged,
|
||||
ChangeMatchesInImplementation,
|
||||
GeneratedAndProvidedMapConflict,
|
||||
SavedOriginalValuesForReferencedChildren,
|
||||
AddedIdleExpression,
|
||||
DelegateArgumentChange,
|
||||
DynamicArguments,
|
||||
NewHandle
|
||||
}
|
||||
|
||||
static class UpdateBlockedReasonMessages
|
||||
{
|
||||
public static string Get(UpdateBlockedReason reason)
|
||||
{
|
||||
switch (reason)
|
||||
{
|
||||
case UpdateBlockedReason.Custom:
|
||||
return SR.BlockedUpdateInsideActivityUpdateError;
|
||||
case UpdateBlockedReason.TypeChange:
|
||||
return SR.DUActivityTypeMismatchRuntime;
|
||||
case UpdateBlockedReason.PublicChildrenChange:
|
||||
return SR.PublicChildrenChangeBlockDU;
|
||||
case UpdateBlockedReason.InvalidImplementationMap:
|
||||
return SR.InvalidImplementationMapRuntime;
|
||||
case UpdateBlockedReason.PrivateMembersHaveChanged:
|
||||
return SR.PrivateMembersHaveChanged;
|
||||
case UpdateBlockedReason.ChangeMatchesInImplementation:
|
||||
return SR.CannotChangeMatchesInImplementation;
|
||||
case UpdateBlockedReason.GeneratedAndProvidedMapConflict:
|
||||
return SR.GeneratedAndProvidedMapConflictRuntime;
|
||||
case UpdateBlockedReason.SavedOriginalValuesForReferencedChildren:
|
||||
return SR.CannotSaveOriginalValuesForReferencedChildren;
|
||||
case UpdateBlockedReason.AddedIdleExpression:
|
||||
return SR.AddedIdleExpressionBlockDU;
|
||||
case UpdateBlockedReason.DelegateArgumentChange:
|
||||
return SR.DelegateArgumentChangeBlockDU;
|
||||
case UpdateBlockedReason.DynamicArguments:
|
||||
return SR.NoDynamicArgumentsInActivityDefinitionChangeRuntime;
|
||||
case UpdateBlockedReason.NewHandle:
|
||||
return SR.CannotAddHandlesUpdateError;
|
||||
default:
|
||||
Fx.Assert("Every block reason should have a corresponding message");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,212 @@
|
||||
// <copyright>
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace System.Activities.DynamicUpdate
|
||||
{
|
||||
using System;
|
||||
using System.Activities.Validation;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class UpdateMapMetadata
|
||||
{
|
||||
private DynamicUpdateMapBuilder.Finalizer finalizer;
|
||||
DynamicUpdateMapBuilder.IDefinitionMatcher matcher;
|
||||
private Activity targetActivity;
|
||||
private bool isDisposed;
|
||||
|
||||
internal UpdateMapMetadata(DynamicUpdateMapBuilder.Finalizer finalizer,
|
||||
DynamicUpdateMapBuilder.IDefinitionMatcher matcher, Activity targetActivity)
|
||||
{
|
||||
this.finalizer = finalizer;
|
||||
this.matcher = matcher;
|
||||
this.targetActivity = targetActivity;
|
||||
this.isDisposed = false;
|
||||
}
|
||||
|
||||
public void AllowUpdateInsideThisActivity()
|
||||
{
|
||||
this.ThrowIfDisposed();
|
||||
this.finalizer.AllowUpdateInsideCurrentActivity = true;
|
||||
this.finalizer.UpdateDisallowedReason = null;
|
||||
}
|
||||
|
||||
public void DisallowUpdateInsideThisActivity(string reason)
|
||||
{
|
||||
this.ThrowIfDisposed();
|
||||
this.finalizer.AllowUpdateInsideCurrentActivity = false;
|
||||
this.finalizer.UpdateDisallowedReason = reason;
|
||||
}
|
||||
|
||||
public void AddMatch(Activity updatedChild, Activity originalChild)
|
||||
{
|
||||
this.ThrowIfDisposed();
|
||||
|
||||
if (updatedChild != null && originalChild != null)
|
||||
{
|
||||
this.matcher.AddMatch(updatedChild, originalChild, this.targetActivity);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddMatch(Variable updatedVariable, Variable originalVariable)
|
||||
{
|
||||
this.ThrowIfDisposed();
|
||||
|
||||
if (updatedVariable != null && originalVariable != null)
|
||||
{
|
||||
this.matcher.AddMatch(updatedVariable, originalVariable, this.targetActivity);
|
||||
}
|
||||
}
|
||||
|
||||
public Activity GetMatch(Activity updatedChild)
|
||||
{
|
||||
this.ThrowIfDisposed();
|
||||
|
||||
if (updatedChild != null)
|
||||
{
|
||||
Activity result = this.matcher.GetMatch(updatedChild);
|
||||
if (updatedChild.MemberOf == this.targetActivity.MemberOf)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else if (result != null)
|
||||
{
|
||||
// GetMatch checks that the activities have the same relationship to declaring parent.
|
||||
// But for referenced children, we also need to check whether they have the same relationship
|
||||
// to referencing parent.
|
||||
// In case of multiple references from the same parent, we'll compare the first one we find.
|
||||
bool updatedIsImport;
|
||||
bool updatedIsReferenced = IsChild(this.TargetActivity, updatedChild, out updatedIsImport);
|
||||
bool updatedIsDelegate = updatedChild.HandlerOf != null;
|
||||
|
||||
bool originalIsImport;
|
||||
bool originalIsReferenced = IsChild(GetMatch(this.TargetActivity), result, out originalIsImport);
|
||||
bool originalIsDelegate = result.HandlerOf != null;
|
||||
|
||||
if (updatedIsReferenced && originalIsReferenced && updatedIsImport == originalIsImport && updatedIsDelegate == originalIsDelegate)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Variable GetMatch(Variable updatedVariable)
|
||||
{
|
||||
this.ThrowIfDisposed();
|
||||
|
||||
if (updatedVariable != null && updatedVariable.Owner == this.TargetActivity)
|
||||
{
|
||||
Variable result = this.matcher.GetMatch(updatedVariable);
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool IsReferenceToImportedChild(Activity childActivity)
|
||||
{
|
||||
this.ThrowIfDisposed();
|
||||
|
||||
if (childActivity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Activity parent = (childActivity.RootActivity == this.TargetActivity.RootActivity) ? this.TargetActivity : GetMatch(this.TargetActivity);
|
||||
return IsReferenceToImportedChild(parent, childActivity);
|
||||
}
|
||||
|
||||
internal bool IsUpdateExplicitlyAllowedOrDisallowed
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.finalizer.AllowUpdateInsideCurrentActivity.HasValue;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Dispose()
|
||||
{
|
||||
this.isDisposed = true;
|
||||
}
|
||||
|
||||
internal bool AreMatch(Activity updatedActivity, Activity originalActivity)
|
||||
{
|
||||
return this.matcher.GetMatch(updatedActivity) == originalActivity;
|
||||
}
|
||||
|
||||
internal bool AreMatch(ActivityDelegate updatedDelegate, ActivityDelegate originalDelegate)
|
||||
{
|
||||
if (updatedDelegate.Handler != null && originalDelegate.Handler != null)
|
||||
{
|
||||
return this.matcher.GetMatch(updatedDelegate.Handler) == originalDelegate.Handler;
|
||||
}
|
||||
else
|
||||
{
|
||||
return updatedDelegate.Handler == null && originalDelegate.Handler == null;
|
||||
}
|
||||
}
|
||||
|
||||
internal DynamicUpdateMapBuilder.Finalizer Finalizer
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.finalizer;
|
||||
}
|
||||
}
|
||||
|
||||
internal Activity TargetActivity
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.targetActivity;
|
||||
}
|
||||
}
|
||||
|
||||
internal void ThrowIfDisposed()
|
||||
{
|
||||
if (this.isDisposed)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new ObjectDisposedException(ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool IsChild(Activity parent, Activity child, out bool isImport)
|
||||
{
|
||||
if (child.HandlerOf == null)
|
||||
{
|
||||
isImport = parent.ImportedChildren.Contains(child);
|
||||
return isImport || parent.Children.Contains(child);
|
||||
}
|
||||
else
|
||||
{
|
||||
isImport = parent.ImportedDelegates.Contains(child.HandlerOf);
|
||||
return isImport || parent.Delegates.Contains(child.HandlerOf);
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsReferenceToImportedChild(Activity parent, Activity child)
|
||||
{
|
||||
if (child != null && child.MemberOf != parent.MemberOf)
|
||||
{
|
||||
IdSpace idSpace = parent.MemberOf.Parent;
|
||||
while (idSpace != null)
|
||||
{
|
||||
if (idSpace == child.MemberOf)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
idSpace = idSpace.Parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user