[jboss-user] [JBoss jBPM] - Re: Task timer and TaskInstance.dueDate field

kukeltje do-not-reply at jboss.com
Fri Sep 12 14:28:29 EDT 2008


1: Sure, no problem... just model it that way

2: leaving the node but keeping the task and 'just' notify? Via Email? That is possible with a timer. Via a new task, leaving the node where to? A new tasknode? And what if the user finishes the task before someone else can react on this task? Do you want to cancel it then? 

Remember that jBPM van have tasks that are not in the flow... you can create and start them when a timer goes off. And e.g. cancel them when a transition is taken on the original node.

Just to show you (and this is a one time effort by me ;-)) I've made an example of this which is even somewhat configurable. 


These are all possible with jBPM *now* just think out of the box and model these things into your process. Or write some code (actionhandlers etc..) The thing is, escalation, or the way people want it, is so dependant on the case, it cannot to the fullest extend be part of the processlanguage. 

The solution for the initial problem 'reported' is to give both the timer and the duedate (which is just for informing the original owner) the same date. but what need is a date for a reminder if when the duedate is reached 


  | package net.vankuijk.jbpm;
  | 
  | import java.util.ArrayList;
  | import java.util.Collection;
  | import java.util.List;
  | import java.util.Map;
  | 
  | import org.apache.commons.logging.Log;
  | import org.apache.commons.logging.LogFactory;
  | import org.jbpm.db.AbstractDbTestCase;
  | import org.jbpm.graph.def.ActionHandler;
  | import org.jbpm.graph.def.Node;
  | import org.jbpm.graph.def.ProcessDefinition;
  | import org.jbpm.graph.exe.ExecutionContext;
  | import org.jbpm.graph.exe.ProcessInstance;
  | import org.jbpm.graph.exe.Token;
  | import org.jbpm.graph.node.TaskNode;
  | import org.jbpm.taskmgmt.def.Task;
  | import org.jbpm.taskmgmt.exe.TaskInstance;
  | import org.jbpm.taskmgmt.exe.TaskMgmtInstance;
  | 
  | public class EscalationExampleTest extends AbstractDbTestCase {
  | 
  | 	ArrayList ownerIDs;
  | 	ArrayList escalatorIDs;
  | 
  | 	List ownerTasks;
  | 	List escalatorTasks;
  | 
  | 	public void setUp() throws Exception {
  | 		super.setUp();
  | 
  | 		ownerIDs = new ArrayList();
  | 		ownerIDs.add("owner");
  | 
  | 		escalatorIDs = new ArrayList();
  | 		escalatorIDs.add("escalator");
  | 
  | 	}
  | 
  | 	static String processDefinition = "<process-definition name='testEscalation'>"
  | 			+ "  <swimlane name='ownerSwimlane'>"
  | 			+ "    <assignment pooled-actors='owner' />"
  | 			+ "  </swimlane>"
  | 
  | 			+ "  <event type='node-leave'>"
  | 			+ "    <action class='net.vankuijk.jbpm.EscalationExampleTest$CancelEscalationTask' />"
  | 			+ "  </event>"
  | 
  | 			+ "  <action name='createEscalationTask' class='net.vankuijk.jbpm.EscalationExampleTest$CreateEscalationTask'>"
  | 			+ "    <escalationTaskNodeName>task escalated</escalationTaskNodeName>"
  | 			+ "  </action>"
  | 
  | 			+ "  <swimlane name='escalationSwimlane'>"
  | 			+ "    <assignment pooled-actors='escalator' />"
  | 			+ "  </swimlane>"
  | 
  | 			+ "  <start-state>"
  | 			+ "    <transition name='to_task' to='task' />"
  | 			+ "  </start-state>"
  | 
  | 			+ "  <task-node name='task'>"
  | 			+ "    <task name='task 0' swimlane='ownerSwimlane'>"
  | 			+ "      <timer duedate='5 seconds'>"
  | 			+ "        <action ref-name='createEscalationTask' />"
  | 			+ "      </timer>"
  | 			+ "    </task>"
  | 			+ "    <transition name='to_end' to='end' />"
  | 			+ "  </task-node>"
  | 
  | 			+ "  <task-node name='task escalated'>"
  | 			+ "    <task name='escalated task 0' swimlane='escalationSwimlane' signalling='false'/>"
  | 			+ "  </task-node>"
  | 
  | 			+ "  <end-state name='end' />"
  | 
  | 			+ "</process-definition>";
  | 
  | 	void deployProcessDefinition(String xml) {
  | 		ProcessDefinition processDefinition = ProcessDefinition
  | 				.parseXmlString(xml);
  | 		jbpmContext.deployProcessDefinition(processDefinition);
  | 		newTransaction();
  | 	}
  | 
  | 	public void testNormalFlow() {
  | 
  | 		deployProcessDefinition(processDefinition);
  | 
  | 		ProcessInstance processInstance = jbpmContext
  | 				.newProcessInstanceForUpdate("testEscalation");
  | 		processInstance.signal();
  | 
  | 		processInstance = saveAndReload(processInstance);
  | 
  | 		ownerTasks = jbpmContext.getGroupTaskList(ownerIDs);
  | 		TaskInstance ownerTask = (TaskInstance) ownerTasks.get(0);
  | 		ownerTask.end();
  | 
  | 		assertEquals(0, processInstance.getTaskMgmtInstance()
  | 				.getUnfinishedTasks(processInstance.getRootToken()).size());
  | 
  | 		assertEquals(true, processInstance.hasEnded());
  | 
  | 	}
  | 
  | 	public void testEndingNormalTaskAfterEscalationCancelsEscalation() {
  | 		deployProcessDefinition(processDefinition);
  | 
  | 		ProcessInstance processInstance = jbpmContext
  | 				.newProcessInstanceForUpdate("testEscalation");
  | 		long piId = processInstance.getId();
  | 		processInstance.signal();
  | 
  | 		assertEquals(1, processInstance.getTaskMgmtInstance()
  | 				.getTaskInstances().size());
  | 
  | 		processInstance = saveAndReload(processInstance);
  | 
  | 		ownerTasks = jbpmContext.getGroupTaskList(ownerIDs);
  | 		assertEquals(1, ownerTasks.size());
  | 
  | 		escalatorTasks = jbpmContext.getGroupTaskList(escalatorIDs);
  | 		assertEquals(0, escalatorTasks.size());
  | 
  | 		processJobs(10000);
  | 
  | 		processInstance = jbpmContext.getProcessInstance(piId);
  | 
  | 		assertEquals(2, processInstance.getTaskMgmtInstance()
  | 				.getTaskInstances().size());
  | 
  | 		escalatorTasks = jbpmContext.getGroupTaskList(escalatorIDs);
  | 		assertEquals(1, escalatorTasks.size());
  | 
  | 		ownerTasks = jbpmContext.getGroupTaskList(ownerIDs);
  | 		TaskInstance ownerTask = (TaskInstance) ownerTasks.iterator().next();
  | 		ownerTask.end();
  | 
  | 		// processInstance = saveAndReload(processInstance);
  | 
  | 		// Escalation task should be cancelled
  | 		escalatorTasks = jbpmContext.getGroupTaskList(escalatorIDs);
  | 		assertEquals(0, escalatorTasks.size());
  | 
  | 	}
  | 
  | 	public void testEscalationEnded_NormalTaskStays() {
  | 		deployProcessDefinition(processDefinition);
  | 
  | 		ProcessInstance processInstance = jbpmContext
  | 				.newProcessInstanceForUpdate("testEscalation");
  | 		long piId = processInstance.getId();
  | 		processInstance.signal();
  | 
  | 		assertEquals(1, processInstance.getTaskMgmtInstance()
  | 				.getTaskInstances().size());
  | 
  | 		processInstance = saveAndReload(processInstance);
  | 
  | 		ownerTasks = jbpmContext.getGroupTaskList(ownerIDs);
  | 		assertEquals(1, ownerTasks.size());
  | 
  | 		escalatorTasks = jbpmContext.getGroupTaskList(escalatorIDs);
  | 		assertEquals(0, escalatorTasks.size());
  | 
  | 		processJobs(10000);
  | 
  | 		processInstance = jbpmContext.getProcessInstance(piId);
  | 
  | 		assertEquals(2, processInstance.getTaskMgmtInstance()
  | 				.getTaskInstances().size());
  | 
  | 		escalatorTasks = jbpmContext.getGroupTaskList(escalatorIDs);
  | 		assertEquals(1, escalatorTasks.size());
  | 
  | 		TaskInstance escalatorTask = (TaskInstance) escalatorTasks.iterator()
  | 				.next();
  | 		assertEquals("escalated task 0", escalatorTask.getName());
  | 		escalatorTask.end();
  | 
  | 		processInstance = saveAndReload(processInstance);
  | 
  | 		// owner task should still be there... is it?
  | 		ownerTasks = jbpmContext.getGroupTaskList(ownerIDs);
  | 		assertEquals(1, ownerTasks.size());
  | 
  | 		escalatorTasks = jbpmContext.getGroupTaskList(escalatorIDs);
  | 		assertEquals(0, escalatorTasks.size());
  | 
  | 	}
  | 
  | 	public static class CreateEscalationTask implements ActionHandler {
  | 		private static final long serialVersionUID = 1L;
  | 
  | 		public String escalationTaskNodeName;
  | 
  | 		public void execute(ExecutionContext executionContext) throws Exception {
  | 
  | 			
  | 			if ("".equals(escalationTaskNodeName) || escalationTaskNodeName == null) {
  | 				log.warn("escalationTaskNodeName not specified");
  | 				return;
  | 			}
  | 
  | 			Token token = executionContext.getToken();
  | 			TaskMgmtInstance tmi = executionContext.getTaskMgmtInstance();
  | 			
  | 			Node node = executionContext.getProcessDefinition().getNode(
  | 					escalationTaskNodeName);
  | 			if (node != null) {
  | 				TaskNode escalatedTaskNode = (TaskNode) node;
  | 
  | 				// assuming 1 task in node... otherwise also use e.g. a param
  | 				// like escalationTaskNodeName. Errorhandling for this not done yet
  | 				Task escalateTask = (Task) escalatedTaskNode.getTasksMap()
  | 						.values().iterator().next();
  | 
  | 				Token childToken = new Token(token, token.getFullName()
  | 						+ "_child_" + token.getChildren().size());
  | 
  | 				childToken.setNode(escalatedTaskNode);
  | 
  | 				tmi.createTaskInstance(escalateTask, childToken);
  | 			} else {
  | 				log.warn("escalationTaskNode with name " + escalationTaskNodeName + " not found.");
  | 			}
  | 
  | 		}
  | 	}
  | 
  | 	public static class CancelEscalationTask implements ActionHandler {
  | 		private static final long serialVersionUID = 1L;
  | 
  | 		public void execute(ExecutionContext executionContext) throws Exception {
  | 
  | 			// Assuming max one active childToken and max one unfinished task in
  | 			// this childtoken
  | 			Map activeChildren = executionContext.getToken()
  | 					.getActiveChildren();
  | 			if (!activeChildren.isEmpty()) {
  | 				Token childToken = (Token) activeChildren.values().iterator()
  | 						.next();
  | 				Collection unfinishedTasks = executionContext
  | 						.getTaskMgmtInstance().getUnfinishedTasks(childToken);
  | 				if (!unfinishedTasks.isEmpty()) {
  | 					((TaskInstance) unfinishedTasks.iterator().next()).cancel();
  | 				}
  | 			}
  | 
  | 		}
  | 	}
  | 
  | 	private static final Log log = LogFactory.getLog(EscalationExampleTest.class);
  | 
  | }
  | 
  | 

Maybe someone wants to make a wiki page out of this....

View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4176232#4176232

Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4176232



More information about the jboss-user mailing list