예제 #1
0
        // this is called after all instances have been loaded and fixedup
        public void UpdateInstanceByActivityParticipation(ActivityExecutor activityExecutor, DynamicUpdateMap rootMap, ref Collection <ActivityBlockingUpdate> updateErrors)
        {
            foreach (InstanceListNeedingUpdate participant in this.updateList)
            {
                if (participant.NothingChanged || participant.ParentIdShiftOnly)
                {
                    Fx.Assert(participant.UpdateMap == null && participant.MapEntry == null, "UpdateMap and MapEntry must be null if we are here.");

                    // create a temporary NoChanges UpdateMap as well as a temporary no change MapEntry
                    // so that we can create a NativeActivityUpdateContext object in order to invoke UpdateInstance() on an activity which
                    // doesn't have a corresponding map and an map entry.
                    // The scenario enabled here is scheduling a newly added reference branch to a Parallel inside an activity's implementation.
                    participant.UpdateMap = DynamicUpdateMap.DummyMap;
                    participant.MapEntry  = DynamicUpdateMapEntry.DummyMapEntry;
                }

                // now let activities participate in update
                for (int i = 0; i < participant.InstanceList.Count; i++)
                {
                    ActivityInstance instance = participant.InstanceList[i] as ActivityInstance;
                    if (instance == null)
                    {
                        continue;
                    }

                    IInstanceUpdatable activity = instance.Activity as IInstanceUpdatable;
                    if (activity != null && instance.SubState == ActivityInstance.Substate.Executing)
                    {
                        NativeActivityUpdateContext updateContext = new NativeActivityUpdateContext(this, activityExecutor, instance, participant.UpdateMap, participant.MapEntry, rootMap);
                        try
                        {
                            activity.InternalUpdateInstance(updateContext);

                            if (updateContext.IsUpdateDisallowed)
                            {
                                ActivityBlockingUpdate.AddBlockingActivity(ref updateErrors, instance.Activity, new QualifiedId(participant.OriginalId).ToString(), updateContext.DisallowedReason, instance.Id);
                                continue;
                            }
                        }
                        catch (Exception e)
                        {
                            if (Fx.IsFatal(e))
                            {
                                throw;
                            }

                            throw FxTrace.Exception.AsError(new InstanceUpdateException(SR.NativeActivityUpdateInstanceThrewException(e.Message), e));
                        }
                        finally
                        {
                            updateContext.Dispose();
                        }
                    }
                }
            }

            // Schedule evaluation of newly added arguments and newly added variables.
            // This needs to happen after all the invokations of UpdateInstance above, so that newly
            // added arguments and newly added variables get evaluated before any newly added activities get executed.
            // We iterate the list in reverse so that parents are always scheduled after (and thus
            // execute before) their children, which may depend on the parents.
            for (int i = this.updateList.Count - 1; i >= 0; i--)
            {
                InstanceListNeedingUpdate participant = this.updateList[i];

                if (!participant.MapEntryExists)
                {
                    // if the given InstanceList has no map entry,
                    // then there is no new LocationReferences to resolve.
                    continue;
                }

                Fx.Assert(participant.MapEntry != null, "MapEntry must be non-null here.");
                if (!participant.MapEntry.HasEnvironmentUpdates)
                {
                    // if there is no environment updates for this MapEntry,
                    // then there is no new LocationReferences to resolve.
                    continue;
                }

                for (int j = 0; j < participant.InstanceList.Count; j++)
                {
                    ActivityInstance instance = participant.InstanceList[j] as ActivityInstance;
                    if (instance == null || instance.SubState != ActivityInstance.Substate.Executing)
                    {
                        // if the given ActivityInstance is not in Substate.Executing,
                        // then, do not try to resolve new LocationReferences
                        continue;
                    }

                    List <int> addedArgumentIndexes;
                    List <int> addedVariableIndexes;
                    List <int> addedPrivateVariableIndexes;

                    EnvironmentUpdateMap envMap = participant.MapEntry.EnvironmentUpdateMap;

                    if (envMap.HasVariableEntries && TryGatherSchedulableExpressions(envMap.VariableEntries, out addedVariableIndexes))
                    {
                        // schedule added variable default expressions
                        instance.ResolveNewVariableDefaultsDuringDynamicUpdate(activityExecutor, addedVariableIndexes, false);
                    }

                    if (envMap.HasPrivateVariableEntries && TryGatherSchedulableExpressions(envMap.PrivateVariableEntries, out addedPrivateVariableIndexes))
                    {
                        // schedule added private variable default expressions
                        // HasPrivateMemberChanged() check disallows addition of private variable default that offsets the private IdSpace,
                        // However, the added private variable default expression can be an imported activity, which has no affect on the private IdSpace.
                        // For such case, we want to be able to schedule the imported default expressions here.
                        instance.ResolveNewVariableDefaultsDuringDynamicUpdate(activityExecutor, addedPrivateVariableIndexes, true);
                    }

                    if (envMap.HasArgumentEntries && TryGatherSchedulableExpressions(envMap.ArgumentEntries, out addedArgumentIndexes))
                    {
                        // schedule added arguments
                        instance.ResolveNewArgumentsDuringDynamicUpdate(activityExecutor, addedArgumentIndexes);
                    }
                }
            }
        }
예제 #2
0
        // 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);
        }