First, let me state that this is in regards to versions 6.4/6.5 of jBPM. It may not be applicable to the upcoming version 7.0, as I have not investigated that version. My current client is using version 6.4.0.Final, and I have verified that the following is still true in version 6.5.0.Final.
Second, let me ask the root question...Is there a simple way to replace/change the behavior of the task deadline service? I know about creating my own implementation of the NotificationListener, and registering it. However, that does not address the ability to affect the mechanism(s) for escalation/reassignment (at least not directly). And that is the challenge I face. The following text talks about why I need the ability to do this, and what I've done in my effort to make this change myself, without forking the jBPM code base. Unfortunately, I've hit a rather significant roadblock to the approach I describe below; which has prompted me to ask the above question.
My current client wants to have tasks assigned in an automated fashion. That means that when a task is being created, a set of business rules is used to first determine candidates for assignment, then other rules rank the candidates for suitability, and finally a candidate is selected as the actual owner of the task. The actual owner is being assigned via the task service's delegate method. This all works well for the initial assignment of the task. But when we add SLA information (i.e. deadlines), the code that is meant to handle the task reassignment is not functioning as desired.
From the execute method found in the org.jbpm.services.task.commands.ExecuteDeadlinesCommand class:
if (!escalation.getReassignments().isEmpty()) {
taskEventSupport.fireBeforeTaskReassigned(task, ctx);
// get first and ignore the rest.
Reassignment reassignment = escalation.getReassignments().get(0);
logger.debug("Reassigning to {}", reassignment.getPotentialOwners());
((InternalTaskData) task.getTaskData()).setStatus(Status.Ready);
List<OrganizationalEntity> potentialOwners = new ArrayList<OrganizationalEntity>(reassignment.getPotentialOwners());
((InternalPeopleAssignments) task.getPeopleAssignments()).setPotentialOwners(potentialOwners);
((InternalTaskData) task.getTaskData()).setActualOwner(null);
taskEventSupport.fireAfterTaskReassigned(task, ctx);
}
As can be seen in the above code snippet, the reassignment information is being retrieved (actually, it's only looking at the first reassignment object...any others are disregarded), and used to create an updated list of potential owners. The highlighted line illustrates the fact that the task is then left in the Ready state, without anyone assigned. Now, it seems like this should be a simple situation to remedy. My first attempt to do so has, however, hit a snag. I'll start by explaining my first attempt to change the behavior involved the following steps...
- Create a replacement for the ExecuteDeadlinesCommand class. We'll call it DeadlineExecutorCommand, and it extends the ExecuteDeadlinesCommand class, overriding the execute method to add our own desired behavior.
- Determine who was creating the ExecuteDeadlinesCommand object, and somehow cause it to create our object instead.
- Instances of the ExecuteDeadlinesCommand object are created by objects that are created from classes defined within the org.jbpm.services.task.impl.TaskDeadlinesServiceImpl class
- The ScheduledTaskDeadline class is used if there is not a GlobalTimerService available. A replacement class was created, that overrides the call method, so that a DeadlineExecutor command is created instead of the ExecuteDeadlinesCommand.
- The TaskDeadlineJob and TaskDeadlineJobContext classes are used if there is a GlobalTimerService. A class was created, to replace the TaskDeadlineJob class. The replacement class overrides the execute method, to create DeadlineExecutorCommand objects instead of ExecuteDeadlinesCommand objects.
- A replacement of the TaskDeadlinesServiceImpl class (nominally named DeadlineServiceImpl) was created, so that the schedule/unschedule methods could be overridden. These methods are what were creating the original ScheduledTaskDeadline and TaskDeadlineJob objects. The replacement class creates our new version of those objects.
- Determine what was creating the TaskDeadlinesServiceImpl object(s), and somehow cause it to create our DeadlineServiceImpl object.
This is the point where we run into issues. I saw that in the org.jbpm.services.task.HumanTaskConfigurator, as part of the
getTaskService method, the TaskDeadlinesServiceImpl is getting initialized. That's easy enough to remedy; create my own version of the HumanTaskConfigurator, and have it initialize the DeadlineServiceImpl instead.
Ahh...if only the AddTaskCommand used the deadlines service that was initialized as part of the getTaskService method. Instead, the AddTaskCommand's execute method uses the passed in TaskContext object to get a TaskDeadlinesServiceImpl object, by calling new TaskDeadlinesServiceImpl to get an instance of the deadline service. This means that the replacement classes are not actually used within the context of the executing process/task. While creating the replacement classes was not difficult, it appears that getting those classes to be used is difficult.
In conclusion, I'll reiterate the foundational question. Is there a simple way to replace/change the task deadline behavior, especially as it relates to the escalation/reassignment functionality?