e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
278 lines
9.2 KiB
C#
278 lines
9.2 KiB
C#
// <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);
|
|
}
|
|
}
|
|
}
|
|
}
|