Exemplo n.º 1
0
            protected override void OnCreateDynamicUpdateMap(NativeActivityUpdateMapMetadata metadata, Activity originalActivity)
            {
                PickBranchBody originalBranchBody = (PickBranchBody)originalActivity;

                if ((originalBranchBody.Action != null && metadata.GetMatch(this.Trigger) == originalBranchBody.Action) || (this.Action != null && metadata.GetMatch(this.Action) == originalBranchBody.Trigger))
                {
                    metadata.DisallowUpdateInsideThisActivity(SR.PickBranchTriggerActionSwapped);
                    return;
                }

                metadata.AllowUpdateInsideThisActivity();
            }
Exemplo n.º 2
0
        private static bool ValidateDUInUnconditionalTransition(NativeActivityUpdateMapMetadata metadata, InternalTransition updatedTransition, InternalTransition originalTransition, out string errorMessage)
        {
            Fx.Assert(originalTransition.IsUnconditional, "Transition should be unconditional in the original definition.");
            Activity originalAction = originalTransition.TransitionDataList[0].Action;

            foreach (TransitionData transitionData in updatedTransition.TransitionDataList)
            {
                Activity updatedAction = transitionData.Action;
                Activity actionMatch = metadata.GetMatch(updatedAction);
                Activity conditionMatch = metadata.GetMatch(transitionData.Condition);

                if ((null == originalAction && null != actionMatch) ||
                    (null != originalAction && null != actionMatch && !object.ReferenceEquals(originalAction, actionMatch)))
                {
                    // Transition.Action is an activity moved from elsewhere within the InternalState
                    errorMessage = SR.MovingActivitiesInStateBlockDU;
                    return false;
                }
            }

            errorMessage = string.Empty;
            metadata.SaveOriginalValue(updatedTransition.Trigger, originalTransition.InternalTransitionIndex);
            return true;
        }
Exemplo n.º 3
0
        protected override void OnCreateDynamicUpdateMap(NativeActivityUpdateMapMetadata metadata, Activity originalActivity)
        {
            Flowchart originalFlowchart = (Flowchart)originalActivity;
            Dictionary <Activity, int> originalActivities = new Dictionary <Activity, int>();

            foreach (FlowNode node in originalFlowchart.reachableNodes)
            {
                if (node.ChildActivity == null)
                {
                    continue;
                }
                if (metadata.IsReferenceToImportedChild(node.ChildActivity))
                {
                    // We can't save original values for referenced children. Also, we can't
                    // reliably combine implementation changes with changes to referenced children.
                    // For now, we just disable this scenario altogether; if we want to support it,
                    // we'll need deeper runtime support.
                    metadata.DisallowUpdateInsideThisActivity(SR.FlowchartContainsReferences);
                    return;
                }
                if (originalActivities.ContainsKey(node.ChildActivity))
                {
                    metadata.DisallowUpdateInsideThisActivity(SR.MultipleFlowNodesSharingSameChildBlockDU);
                    return;
                }

                originalActivities[node.ChildActivity] = node.Index;
            }

            HashSet <Activity> updatedActivities = new HashSet <Activity>();

            foreach (FlowNode node in this.reachableNodes)
            {
                if (node.ChildActivity != null)
                {
                    if (metadata.IsReferenceToImportedChild(node.ChildActivity))
                    {
                        metadata.DisallowUpdateInsideThisActivity(SR.FlowchartContainsReferences);
                        return;
                    }

                    if (updatedActivities.Contains(node.ChildActivity))
                    {
                        metadata.DisallowUpdateInsideThisActivity(SR.MultipleFlowNodesSharingSameChildBlockDU);
                        return;
                    }
                    else
                    {
                        updatedActivities.Add(node.ChildActivity);
                    }

                    Activity originalChild = metadata.GetMatch(node.ChildActivity);
                    int      originalIndex;
                    if (originalChild != null && originalActivities.TryGetValue(originalChild, out originalIndex))
                    {
                        if (originalFlowchart.reachableNodes[originalIndex].GetType() != node.GetType())
                        {
                            metadata.DisallowUpdateInsideThisActivity(SR.CannotMoveChildAcrossDifferentFlowNodeTypes);
                            return;
                        }

                        if (originalIndex != node.Index)
                        {
                            metadata.SaveOriginalValue(node.ChildActivity, originalIndex);
                        }
                    }
                }
            }
        }
Exemplo n.º 4
0
        private static bool ValidateDUInConditionTransition(NativeActivityUpdateMapMetadata metadata, InternalTransition updatedTransition, InternalTransition originalTransition, out string errorMessage)
        {
            Fx.Assert(!originalTransition.IsUnconditional, "Transition should be conditional in the original definition.");
            errorMessage = string.Empty;

            foreach (TransitionData updatedTData in updatedTransition.TransitionDataList)
            {
                if (metadata.IsReferenceToImportedChild(updatedTData.Condition))
                {
                    // if the trigger is referenced, it might have another save values already.
                    errorMessage = SR.TriggerOrConditionIsReferenced;
                    return false;
                }

                Fx.Assert(null != updatedTData.Condition, "Must be a condition transition.");
                Activity conditionMatch = metadata.GetMatch(updatedTData.Condition);

                if (null == conditionMatch && null != metadata.GetMatch(updatedTData.Action))
                {
                    // new Transition.Condition with an Transition.Action moved from within the InternalState.
                    errorMessage = SR.MovingActivitiesInStateBlockDU;
                    return false;
                }
                else if (null != conditionMatch)
                {
                    bool foundMatchingOriginalCondition = false;

                    for (int transitionIndex = 0; transitionIndex < originalTransition.TransitionDataList.Count; transitionIndex++)
                    {
                        if (object.ReferenceEquals(originalTransition.TransitionDataList[transitionIndex].Condition, conditionMatch))
                        {
                            foundMatchingOriginalCondition = true;

                            // found the original matching condition in updated transition definition.
                            TransitionData originalTData = originalTransition.TransitionDataList[transitionIndex];

                            Activity originalAction = originalTData.Action;

                            // NOTE: Transition.Action is allowed to be removed, because it doesn't change the execution semantics of SM
                            // if this removed activity was executing, WF runtime would disallow the update.
                            Activity actionMatch = metadata.GetMatch(updatedTData.Action);

                            if (null != actionMatch && !object.ReferenceEquals(originalAction, actionMatch))
                            {
                                // Transition.Action is an activity moved from elsewhere within the InternalState
                                errorMessage = SR.MovingActivitiesInStateBlockDU;
                                return false;
                            }

                            metadata.SaveOriginalValue(updatedTransition.Trigger, originalTransition.InternalTransitionIndex);
                            metadata.SaveOriginalValue(updatedTData.Condition, transitionIndex);
                        }
                    }

                    if (!foundMatchingOriginalCondition)
                    {
                        // another child activity is move to the Transition.Condition.
                        errorMessage = SR.DUDisallowIfCannotFindingMatchingCondition;
                        return false;
                    }
                }
            }

            return true;
        }
Exemplo n.º 5
0
        protected override void OnCreateDynamicUpdateMap(NativeActivityUpdateMapMetadata metadata, Activity originalActivity)
        {
            InternalState originalInternalState = (InternalState)originalActivity;

            // NOTE: State.Entry/Exit are allowed to be removed, because it doesn't change the execution semantics of SM
            // if this removed activity was executing, WF runtime would disallow the update.
            Activity entryActivityMatch = metadata.GetMatch(this.Entry);
            Activity exitActivityMatch = metadata.GetMatch(this.Exit);

            if ((null != entryActivityMatch && !object.ReferenceEquals(entryActivityMatch, originalInternalState.Entry)) ||
                (null != exitActivityMatch && !object.ReferenceEquals(exitActivityMatch, originalInternalState.Exit)))
            {
                // original State.Entry/Exit is replaced with another child activities with InternalState
                // new State.Entry/Exit is moved from another child activities within InternalState.
                metadata.DisallowUpdateInsideThisActivity(SR.MovingActivitiesInStateBlockDU);
                return;
            }

            int originalTriggerInUpdatedDefinition = 0;
            
            foreach (InternalTransition originalTransition in originalInternalState.internalTransitions)
            {
                if (metadata.IsReferenceToImportedChild(originalTransition.Trigger))
                {
                    metadata.DisallowUpdateInsideThisActivity(SR.TriggerOrConditionIsReferenced);
                    return;
                }
                
                if (!originalTransition.IsUnconditional)
                {
                    // new Trigger activity
                    foreach (TransitionData transitionData in originalTransition.TransitionDataList)
                    {
                        if (metadata.IsReferenceToImportedChild(transitionData.Condition))
                        {
                            metadata.DisallowUpdateInsideThisActivity(SR.TriggerOrConditionIsReferenced);
                            return;
                        }
                    }
                }
            }

            foreach (InternalTransition updatedTransition in this.internalTransitions)
            {
                if (metadata.IsReferenceToImportedChild(updatedTransition.Trigger))
                {
                    // if the trigger is referenced, it might have another save values already.
                    metadata.DisallowUpdateInsideThisActivity(SR.TriggerOrConditionIsReferenced);
                    return;
                }

                Activity triggerMatch = metadata.GetMatch(updatedTransition.Trigger);

                if (null != triggerMatch)
                {
                    InternalTransition originalTransition;

                    if (originalInternalState.triggerInternalTransitionMapping.TryGetValue(triggerMatch, out originalTransition))
                    {
                        originalTriggerInUpdatedDefinition++;

                        if (originalTransition.IsUnconditional)
                        {
                            string errorMessage;
                            bool canTransitionBeUpdated = ValidateDUInUnconditionalTransition(metadata, updatedTransition, originalTransition, out errorMessage);

                            if (!canTransitionBeUpdated)
                            {
                                metadata.DisallowUpdateInsideThisActivity(errorMessage);
                                return;
                            }
                        }
                        else
                        {
                            if (updatedTransition.IsUnconditional)
                            {
                                // cannot change the transition from condition to unconditional.
                                metadata.DisallowUpdateInsideThisActivity(SR.ChangeConditionalTransitionToUnconditionalBlockDU);
                                return;
                            }
                            else
                            {
                                string errorMessage;
                                bool canTransitionBeUpdated = ValidateDUInConditionTransition(metadata, updatedTransition, originalTransition, out errorMessage);

                                if (!canTransitionBeUpdated)
                                {
                                    metadata.DisallowUpdateInsideThisActivity(errorMessage);
                                    return;
                                }
                            }
                        }
                    }
                    else
                    {
                        // the trigger is an child activity moved from elsewhere within the state
                        metadata.DisallowUpdateInsideThisActivity(SR.MovingActivitiesInStateBlockDU);
                        return;
                    }
                }
                else
                {
                    // new Trigger activity
                    foreach (TransitionData transitionData in updatedTransition.TransitionDataList)
                    {
                        if ((null != transitionData.Condition && null != metadata.GetMatch(transitionData.Condition)) ||
                            (null != transitionData.Action && null != metadata.GetMatch(transitionData.Action)))
                        {
                            // if a new transition is added, it is expected that the Condition/Action 
                            // are newly created.
                            metadata.DisallowUpdateInsideThisActivity(SR.ChangingTriggerOrUseOriginalConditionActionBlockDU);
                            return;
                        }
                    }
                }
            }
            
            if (originalTriggerInUpdatedDefinition != originalInternalState.internalTransitions.Count)
            {
                // NOTE: in general, if the transition is removed when there are pending triggers,
                // runtime would be able to detect the missing child activities.  However, in cases,
                // where the transition is happening already (in between completion of Transition.Action
                // callback but before InternalState is completed), the workflow definition can be unloaded
                // and updated.  The InternalState is unable to trace the original transition that set the 
                // destination state index.  In that case, the update would fail at UpdateInstance.
                // To simplify the model, it is more convenient to disallow removing existing transitions
                // from an executing InternalState.  The only extra restriction it brings, is that it disables
                // update even if the InternalState is uploaded at State.Entry.  This scenario, however, is uncommon.
                metadata.DisallowUpdateInsideThisActivity(SR.RemovingTransitionsBlockDU);
            }
        }