Dynamic Tasks In Activiti


Here is a hypothetical requirement:
We are talking about a help desk system here. When an incident occurs, a human task is created and assigned to the help desk supervisor. Supervisor may fix it himself and complete the task. As of now, this is standard activiti human task.
Now the supervisor may need to ask the idea of network admin. And/or he may need to ask oracle dba to do something. He needs to add unlimitted number of tasks, assigned to various actors.
Now it is more complex, but again could be implemented with SubTask undocumented feature of actviti.
In the next level, in some cases the supervisor may need to add two  or more consecutive task instead of one single task. Suppose that he wants to get the idea of Oracle DBA and forward it automatically to the software developer. Each of  the following actors, may in turn do the same thing which the supervisor can do. They in turn, may add one, two or more step task series to the process.
The process shall continue, when all the created tasks are completed.

Here is where it gets interesting.

Solution interface:
Here is what I came to, to address requirements.
Let’s start from the high level diagram.

After the start of the process, Service task creates the first dynamic task. Java delegate class simply calls  function from DynaTaskService service:

public class DynamicTaskDelegate implements JavaDelegate {
   public void execute(DelegateExecution execution) throws Exception {
      MyUnitTest.dynaTaskService.createOneTask((ExecutionEntity) execution);

This will create a dynamic with special behavior. Actually in the DynaTaskService two methods avalable. One for creating one single dynamic task, the other one for two consecutive dynamic tasks:

public interface DynaTaskService  {
    public void createOneTask(ExecutionEntity execution);
    public void createTwoTasks(ExecutionEntity execution);

calling createOneTask will create an instance of the unattached single User task, you can see in the diagram. Similarly the createTwoTasks function, creates an instance of unattached sequence of two consecutive tasks.
The next actors, can also call the same methods to create as many tasks as required.
Creating each task causes a counter process variable to be increased.

The magic happens when a task is completed using taskService.completeTask if the task is a dynamic one and there is some other task following, it will be executed as usual. But if the task is dynamic and it is the end task, then another counter, counting number of completed tasks will be increased, line of execution will be terminated, and the receive task is signalled. The gateway after receive task, checkes if the number of completed tasks are equal to number of created tasks. If there are still open tasks, then the loop continues.

This fully addresses the strange non usual requested functionality.

But let’s see how it works under the hood:

How it works:
Tasks are created by calling createOneTask or createTwoTask.
When called createt task function does these steps:

  • increase the counter for created tasks, create if it does not already exist
  • creates seperate execution for the new task
  • create a new task regarding a specific naming convention, with the proper activity name already available in Diagram
  • relates the created task to the created execution

user can call the create task functions arbitarily. The normal activity behavior for these kind of dynamically created task is simply to remove them, and remove the execution if nothing is coming afterwards. This is not exactly what we want.
To change this behavior, we need to override default activiti behavior for completing tasks. Here MyCustomActivitiBehaviorFactory factory comes into the play. It creates our custom behavior MyUserTaskActiviyBehavior when asked by engine.
The most important part of logic is handled in MyUserTaskActivityBehavior. Here is a list to show what is done in the behavior in short:

  • Using name of the task, determine if it is a dynatask. It is not used right now, but may become handy.
  • if there is an outgoing sequence, just follow it normally
  • if there is no outgoing sequence, it means the task is at the end of execution. increase completed tasks counter, end the signal the recieve task on the parent execution

The source file is available in github

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.