private void ProcessTransitions(NativeActivityMetadata metadata) { for (int i = 0; i < this.Transitions.Count; i++) { Transition transition = this.Transitions[i]; InternalTransition internalTransition = null; Activity triggerActivity = transition.ActiveTrigger; if (!_triggerInternalTransitionMapping.TryGetValue(triggerActivity, out internalTransition)) { metadata.AddChild(triggerActivity); internalTransition = new InternalTransition { Trigger = triggerActivity, InternalTransitionIndex = _internalTransitions.Count, }; _triggerInternalTransitionMapping.Add(triggerActivity, internalTransition); _internalTransitions.Add(internalTransition); } AddTransitionData(metadata, internalTransition, transition); } }
private void OnConditionComplete(NativeActivityContext context, ActivityInstance completedInstance, bool result) { StateMachineEventManager eventManager = this.EventManager.Get(context); int triggerId = eventManager.CurrentBeingProcessedEvent.TriggedId; if (result) { this.TakeTransition(context, eventManager, triggerId); } else { // condition failed: reschedule trigger int currentConditionIndex = eventManager.CurrentConditionIndex; Fx.Assert(eventManager.CurrentConditionIndex >= 0, "Conditional Transition must have non-negative index."); InternalTransition transition = this.GetInternalTransition(triggerId); currentConditionIndex++; if (currentConditionIndex < transition.TransitionDataList.Count) { eventManager.CurrentConditionIndex = currentConditionIndex; context.ScheduleActivity <bool>(transition.TransitionDataList[currentConditionIndex].Condition, _onConditionComplete, null); } else { // Schedule current trigger again firstly. context.ScheduleActivity(transition.Trigger, _onTriggerComplete); _currentRunningTriggers.Set(context, _currentRunningTriggers.Get(context) + 1); // check whether there is any other trigger completed. ProcessNextTriggerCompletedEvent(context, eventManager); } } }
private void OnTriggerComplete(NativeActivityContext context, ActivityInstance completedInstance) { int runningTriggers = _currentRunningTriggers.Get(context); _currentRunningTriggers.Set(context, --runningTriggers); bool isOnExit = _isExiting.Get(context); if (!context.IsCancellationRequested && runningTriggers == 0 && isOnExit) { this.ScheduleExit(context); } else if (completedInstance.State == ActivityInstanceState.Closed) { InternalTransition internalTransition = null; _triggerInternalTransitionMapping.TryGetValue(completedInstance.Activity, out internalTransition); Fx.Assert(internalTransition != null, "internalTransition should be added into triggerInternalTransitionMapping in CacheMetadata."); StateMachineEventManager eventManager = this.EventManager.Get(context); bool canBeProcessedImmediately; eventManager.RegisterCompletedEvent( new TriggerCompletedEvent { Bookmark = _evaluateConditionBookmark.Get(context), TriggedId = internalTransition.InternalTransitionIndex }, out canBeProcessedImmediately); if (canBeProcessedImmediately) { ProcessNextTriggerCompletedEvent(context, eventManager); } } }
//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); // } //} //protected override void UpdateInstance(NativeActivityUpdateContext updateContext) //{ // StateMachineEventManager eventManager = updateContext.GetValue(this.EventManager) as StateMachineEventManager; // Fx.Assert(eventManager != null, "eventManager is available in every internalActivity."); // if (eventManager.CurrentBeingProcessedEvent != null || eventManager.Queue.Any()) // { // // Updated state is evaluating conditions or transitioning to another state, // // Then we need to update the index of the current evaluated trigger (in case the trigger is moved) // // and the condition index. // // if the state is transitioning already, then we should update destination state id. // bool isUpdateSuccessful = this.UpdateEventManager(updateContext, eventManager); // if (!isUpdateSuccessful) // { // updateContext.DisallowUpdate(SR.DUTriggerOrConditionChangedDuringTransitioning); // return; // } // if (updateContext.GetValue(this.isExiting) != true) // { // this.RescheduleNewlyAddedTriggers(updateContext); // } // } // else if (updateContext.GetValue(this.currentRunningTriggers) > 0) // { // Fx.Assert(updateContext.GetValue(this.isExiting) != true, "No triggers have completed, state should not be transitioning."); // // the state is not transitioning yet and is persisted at trigger. // this.RescheduleNewlyAddedTriggers(updateContext); // } //} private static void AddTransitionData(NativeActivityMetadata metadata, InternalTransition internalTransition, Transition transition) { TransitionData transitionData = new TransitionData(); Activity <bool> condition = transition.Condition; transitionData.Condition = condition; if (condition != null) { metadata.AddChild(condition); } Activity action = transition.Action; transitionData.Action = action; if (action != null) { metadata.AddChild(action); } if (transition.To != null) { transitionData.To = transition.To.InternalState; } internalTransition.TransitionDataList.Add(transitionData); }
private void TakeTransition(NativeActivityContext context, StateMachineEventManager eventManager, int triggerId) { this.EventManager.Get(context).OnTransition = true; InternalTransition transition = this.GetInternalTransition(triggerId); if (transition.IsUnconditional) { Fx.Assert(-1 == eventManager.CurrentConditionIndex, "CurrentConditionIndex should be -1, if the transition is unconditional."); this.PrepareForExit(context, this.GetTo(triggerId)); } else { Fx.Assert(-1 != eventManager.CurrentConditionIndex, "CurrentConditionIndex should not be -1, if the transition is conditional."); this.PrepareForExit(context, this.GetTo(triggerId, eventManager.CurrentConditionIndex)); } }
private void ScheduleAction(NativeActivityContext context) { StateMachineEventManager eventManager = this.EventManager.Get(context); if (eventManager.IsReferredByBeingProcessedEvent(_evaluateConditionBookmark.Get(context))) { InternalTransition transition = this.GetInternalTransition(eventManager.CurrentBeingProcessedEvent.TriggedId); Activity action = transition.TransitionDataList[-1 == eventManager.CurrentConditionIndex ? 0 : eventManager.CurrentConditionIndex].Action; if (action != null) { context.ScheduleActivity(action); } } this.RemoveBookmarks(context); }
private void StartEvaluateCondition(NativeActivityContext context, Bookmark bookmark, object value) { // Start to evaluate conditions of the trigger which represented by currentTriggerIndex StateMachineEventManager eventManager = this.EventManager.Get(context); int triggerId = eventManager.CurrentBeingProcessedEvent.TriggedId; InternalTransition transition = this.GetInternalTransition(triggerId); if (transition.IsUnconditional) { eventManager.CurrentConditionIndex = -1; this.TakeTransition(context, eventManager, triggerId); } else { eventManager.CurrentConditionIndex = 0; context.ScheduleActivity <bool>( this.GetCondition( triggerId, eventManager.CurrentConditionIndex), _onConditionComplete, null); } }