// targetDefinition argument is optional. private IList <InstanceListNeedingUpdate> GetInstanceListsNeedingUpdate(DynamicUpdateMap updateMap, Activity targetDefinition, List <ActivityInstance> secondaryRootInstances, ref Collection <ActivityBlockingUpdate> updateErrors) { IList <InstanceListNeedingUpdate> instanceListsToUpdate = new List <InstanceListNeedingUpdate>(); if (this.rawDeserializedLists == null) { // This instance doesn't have any active instances (it is complete). return(instanceListsToUpdate); } IdSpace rootIdSpace = null; if (targetDefinition != null) { rootIdSpace = targetDefinition.MemberOf; } for (int i = 0; i < this.rawDeserializedLists.Length; i++) { InstanceList list = this.rawDeserializedLists[i]; QualifiedId oldQualifiedId = new QualifiedId(list.ActivityId); if (updateMap.IsImplementationAsRoot) { int[] oldIdArray = oldQualifiedId.AsIDArray(); if (oldIdArray.Length == 1 && oldIdArray[0] != 1) { throw FxTrace.Exception.AsError(new InstanceUpdateException(SR.InvalidImplementationAsWorkflowRootForRuntimeState)); } } string error; InstanceListNeedingUpdate update; DynamicUpdateMap.UpdatedActivity updatedActivity = updateMap.GetUpdatedActivity(oldQualifiedId, rootIdSpace); if (CanCompensationOrConfirmationHandlerReferenceAddedSymbols(list, updateMap, rootIdSpace, secondaryRootInstances, ref updateErrors)) { update = null; } else if (updatedActivity.MapEntry == null) { if (updatedActivity.IdChanged) { // this newQualifiedId is the new id for those InstanceLists whose IDs shifted by their parents' ID change update = new InstanceListNeedingUpdate { InstanceList = list, NewId = updatedActivity.NewId }; } else { // nothing changed, no map, no mapEntry update = new InstanceListNeedingUpdate { InstanceList = list, NewId = null, }; } } else if (updatedActivity.MapEntry.IsParentRemovedOrBlocked) { update = null; } else if (IsRemovalOrRTUpdateBlockedOrBlockedByUser(updatedActivity, oldQualifiedId, out error)) { string instanceId = null; for (int j = 0; j < list.Count; j++) { ActivityInstance activityInstance = list[j] as ActivityInstance; if (activityInstance != null) { instanceId = activityInstance.Id; break; } } AddBlockingActivity(ref updateErrors, updatedActivity, oldQualifiedId, error, instanceId); update = null; } else if (IsInvalidEnvironmentUpdate(list, updatedActivity, ref updateErrors)) { update = null; } else { // no validation error for this InstanceList // add it to the list of InstanceLists to be updated update = new InstanceListNeedingUpdate { InstanceList = list, NewId = updatedActivity.NewId, UpdateMap = updatedActivity.Map, MapEntry = updatedActivity.MapEntry, NewActivity = updatedActivity.NewActivity }; } if (update != null) { update.OriginalId = list.ActivityId; instanceListsToUpdate.Add(update); } } return(instanceListsToUpdate); }
private static bool CanCompensationOrConfirmationHandlerReferenceAddedSymbols(InstanceList instanceList, DynamicUpdateMap rootUpdateMap, IdSpace rootIdSpace, List <ActivityInstance> secondaryRootInstances, ref Collection <ActivityBlockingUpdate> updateErrors) { for (int j = 0; j < instanceList.Count; j++) { ActivityInstance activityInstance = instanceList[j] as ActivityInstance; if (activityInstance == null || !IsNonDefaultSecondaryRoot(activityInstance, secondaryRootInstances)) { continue; } // here, find out if the given non-default secondary root references an environment to which a symbol is to be added via DU. // we start from a secondary root instead of starting from the enviroment with the already completed owner that was added symbols. // It is becuase for the case of adding symbols to noSymbols activities, the environment doesn't even exist from which we can start looking for referencing secondary root. int[] secondaryRootOriginalQID = new QualifiedId(instanceList.ActivityId).AsIDArray(); Fx.Assert(secondaryRootOriginalQID != null && secondaryRootOriginalQID.Length > 1, "CompensationParticipant is always an implementation child of a CompensableActivity, therefore it's IdSpace must be at least one level deep."); int[] parentOfSecondaryRootOriginalQID = new int[secondaryRootOriginalQID.Length - 1]; Array.Copy(secondaryRootOriginalQID, parentOfSecondaryRootOriginalQID, secondaryRootOriginalQID.Length - 1); List <int> currentQIDBuilder = new List <int>(); for (int i = 0; i < parentOfSecondaryRootOriginalQID.Length; i++) { // // for each iteration of this for-loop, // we are finding out if at every IdSpace level the map has any map entry whose activity has the CompensableActivity as an implementation decendant. // The map may not exist for every IdSpace between the root and the CompensableActivity. // If the matching map and the entry is found, then we find out if that matching entry's activity is a public decendant of any NoSymbols activity DU is to add variables or arguments to. // // This walk on the definition activity tree determines the hypothetical execution-time chain of instances and environments. // The ultimate goal is to prevent adding variables or arguments to a NoSymbols activity which has already completed, // but its decendant CompensableActivity's compensation or confirmation handlers in the future may need to reference the added variables or arguments. currentQIDBuilder.Add(parentOfSecondaryRootOriginalQID[i]); DynamicUpdateMap.UpdatedActivity updatedActivity = rootUpdateMap.GetUpdatedActivity(new QualifiedId(currentQIDBuilder.ToArray()), rootIdSpace); if (updatedActivity.MapEntry != null) { // the activity of this entry either has the CompensableActivity as an implementation decendant, or is the CompensableActivity itself. // walk the same-IdSpace-parent chain of the entry, // look for an entry whose EnvironmentUpdateMap.IsAdditionToNoSymbols is true. DynamicUpdateMapEntry entry = updatedActivity.MapEntry; do { if (!entry.IsRemoval && entry.HasEnvironmentUpdates && entry.EnvironmentUpdateMap.IsAdditionToNoSymbols) { int[] noSymbolAddActivityIDArray = currentQIDBuilder.ToArray(); noSymbolAddActivityIDArray[noSymbolAddActivityIDArray.Length - 1] = entry.OldActivityId; QualifiedId noSymbolAddActivityQID = new QualifiedId(noSymbolAddActivityIDArray); DynamicUpdateMap.UpdatedActivity noSymbolAddUpdatedActivity = rootUpdateMap.GetUpdatedActivity(noSymbolAddActivityQID, rootIdSpace); AddBlockingActivity(ref updateErrors, noSymbolAddUpdatedActivity, noSymbolAddActivityQID, SR.VariableOrArgumentAdditionToReferencedEnvironmentNoDUSupported, null); return(true); } entry = entry.Parent; } while (entry != null); } } } return(false); }