Friday, July 30, 2010

Adding task nodes dynamically at runtime

I find that sometimes there's a good reason not to include all possible paths in a process definition at design time. Some of the more generic, non-functional paths can be included dynamically at runtime, in order not to clutter the process definition and be able to focus on the 'real' functionality your process needs to automate.

This goes e.g. for the handling of exceptions, as described here, where an automatic retry is accomplished by adding a transition dynamically from a node in which an exception occurs to itself. You probably don't want to add such 'self-transitions' at design time (that's just butt-ugly).

When you add such a path, it may include a TaskNode at some point. It did for me, and this is how I solved that.

The following code needs to run inside a jBPM context (obviously):

private void createDynamicTaskNode(ProcessInstance procInst, Node originatingNode, Node targetNode) {
        // Add the dynamic task node.
        // - Create the task.
        Task task = new Task("Dynamic task name");
        task.setProcessDefinition(procInst.getProcessDefinition());
        procInst.getTaskMgmtInstance().getTaskMgmtDefinition().addTask(task);
        task.setPooledActorsExpression("Dynamic task executors"); // Or use an actor ID.
        // - Create the node.
        TaskNode taskNode = new TaskNode("Dynamic task node name");
        taskNode.addTask(task); // Adds both ends of the association TaskNode <-> Task.
        procInst.getProcessDefinition().addNode(taskNode); // Adds both ends of the association ProcessDefinition <-> Node.

        // Create transition between originating node and dynamic task node.
        Transition transition = new Transition("Transition to dynamic task node");
        originatingNode.addLeavingTransition(transition);
        taskNode.addArrivingTransition(transition);
        // Create transition between dynamic task node and target node.
        transition = new Transition();
        taskNode.addLeavingTransition(transition);
        targetNode.addArrivingTransition(transition);
    }

Basically it follows the same scenario for creating the node and transitions as jBPM does when it parses the JPDL process definition, using a lot of the defaults involved (such as that the task is blocking and ending it will signal the process instance to continue).
If you needs any of the non-standard options, you may want to read the manual to see what these options can bring you.