/// <summary> /// Transition completed - consume input tokens, produce output tokens /// and cancel all transitions that share the same tokens. /// Also, if some tokens were waiting, put them in 'READY' state. /// Wow, looks quite complex. /// TODO: fix case when transition completion removes token from /// some or-join checklist /// </summary> /// <param name="at"></param> private void AfterTransitionCompleted(string correlationId) { lock (this) { TaskShell at = GetActiveTransition(correlationId); if (at == null) throw new Exception("Invalid correlation Id"); log.Info("Transition completed: {0}", at); if (at.Status != TransitionStatus.ENABLED && at.Status != TransitionStatus.STARTED) throw new Exception("Invalid transition status"); Task tsk = Definition.GetTask(at.TaskId); if (at.Status == TransitionStatus.ENABLED) { AfterTransitionSelected(correlationId); } Debug.Assert(at.Status == TransitionStatus.STARTED); //1. transfer task output data from transition at.TransferTaskOutputDataToParent(GetProcessVariablesContainer()); ValidateProcessInternalData(); at.Status = TransitionStatus.COMPLETED; //handle cancel set if (tsk.CancelSet.Count > 0) { log.Info("Handling cancel set of task {0}", tsk.Id); foreach (string plid in tsk.CancelSet) { RemoveAllTokensInPlace(plid); } } //and produce output tokens int cnt = 0; if (tsk.SplitType == JoinType.AND) { foreach (Flow fl in tsk.FlowsOut) { if (fl.InputCondition != null && fl.InputCondition.Length > 0) throw new Exception(); AddToken(fl.To.Id); cnt++; } } else if (tsk.SplitType == JoinType.XOR) { IList<Flow> flows = tsk.FlowsOutOrdered; for (int i = 0; i < flows.Count; i++) { if (i == flows.Count - 1) { //last flow - the default one. Always add a token if we are here AddToken(flows[i].To.Id); cnt++; } else { if (EvaluateFlowInputCondition(flows[i])) { AddToken(flows[i].To.Id); cnt++; break; } } } } else if (tsk.SplitType == JoinType.OR) { IList<Flow> flows = tsk.FlowsOutOrdered; for (int i = 0; i < flows.Count; i++) { if (EvaluateFlowInputCondition(flows[i])) { AddToken(flows[i].To.Id); cnt++; } } if (cnt == 0) { //we haven't created any tokens, created the default one AddToken(flows[flows.Count - 1].To.Id); cnt++; } } else throw new Exception(); if (cnt == 0) throw new Exception("Transition completion did not produce any tokens"); //5 notify others ActiveTransitionCompleted compl = new ActiveTransitionCompleted(); compl.CorrelationId = at.CorrelationId; compl.InstanceId = this.InstanceId; compl.TaskId = at.TaskId; compl.TaskType = tsk.GetType().Name; compl.TimeStamp = DateTime.Now; compl.DefinitionId = this.ProcessDefinitionId; NotifyProcessEvent(compl); } }
/// <summary> /// Transition completed - consume input tokens, produce output tokens /// and cancel all transitions that share the same tokens. /// Also, if some tokens were waiting, put them in 'READY' state. /// Wow, looks quite complex. /// </summary> /// <param name="at"></param> private void AfterTransitionCompleted(string correlationId) { TaskShell at = _activeTransitions[correlationId]; log.Info("Transition completed: {0}", at.CorrelationId); Task tsk = Definition.GetTask(at.TaskId); //1 select the transition for processing bool found = false; foreach (string t in at.Tokens) { Token tok = GetToken(t); Debug.Assert(tok.Status == TokenStatus.LOCKED_ENABLED || tok.Status == TokenStatus.LOCKED_ALLOCATED); if (tok.Status == TokenStatus.LOCKED_ENABLED) { found = true; break; } } if (found) { AfterTransitionSelected(correlationId); } IList<TaskShell> sharedTrans = GetSharedActiveTransitionsForTransition(at); Debug.Assert(sharedTrans.Count == 0); //after transition selected there should be no shared trans. foreach (string tokid in at.Tokens) { Token tok = GetToken(tokid); Debug.Assert(tok.Status == TokenStatus.LOCKED_ALLOCATED); } //at.TaskCompleted(); //at.Status = TransitionStatus.COMPLETED; //2 retrieve data from transition TransferDataFromTransition(at); //3 cancel set handling if (tsk.CancelSet.Count > 0) { log.Debug("Transition {0} ({1}) has cancel set with {2} elements", tsk.Id, at.CorrelationId, tsk.CancelSet.Count); foreach (string placeId in tsk.CancelSet) { IList<Token> tokensInPlace = GetTokensInPlace(placeId); foreach (Token tok in tokensInPlace) { if (tok.Status == TokenStatus.READY || tok.Status == TokenStatus.LOCKED_ENABLED || tok.Status == TokenStatus.LOCKED_ALLOCATED || tok.Status == TokenStatus.WAITING) { log.Debug("Cancelling token {0} in place {1}", tok.TokenId, placeId); CancelToken(tok); } } } } //4 move the tokens UpdateNetStatusAfterTransition(at); //5 notify others ActiveTransitionCompleted compl = new ActiveTransitionCompleted(); compl.CorrelationId = at.CorrelationId; compl.InstanceId = this.InstanceId; compl.TaskId = at.TaskId; compl.TaskType = tsk.GetType().Name; compl.TimeStamp = DateTime.Now; compl.DefinitionId = this.ProcessDefinitionId; NotifyProcessEvent(compl); }