cancel
Showing results for 
Search instead for 
Did you mean: 

Dynamic assignment

hmartim
Champ in-the-making
Champ in-the-making
Hi,

an excellent extension of the Activiti is the possibility of defining "activiti:assignee" and "activiti:candidateUsers" of a UserTask via a Spring bean operation like "$ {ldapService.findManagerForEmployee (loan)}" or "$ {ldapService.findAllSales ()}".

This allows dynamic definition of resources for a UserTask, similar to the "parametrized Resource/Role" of BPMN 2.0.

However, there are some situations in which resources dynamically retrieved in the creation of UserTask (which are responsible for the task) may change while the task has not yet been assigned or completed. For example, the employee's manager was replaced, so a new person/user is responsable for the task.

Could the engine offer a way to recover the UserTasks whose responsables were defined by a method (Spring Bean)? And still offer a operation, for example, that allow re-run this definition of responsables (or assignee canditateUsers) of these tasks?

Thus, a processing of the application could periodically (or as consequence of some event) trigger the engine to make this update.

Or is there another way to do this update?

Thanks,
Hudson.
14 REPLIES 14

frederikherema1
Star Contributor
Star Contributor
Hi,

Nothing built in into the engine to re-calculate the assignee/candidates, only happens when task is created. You could however write your own logic that , when manager changes for example, you query all tasks that are assigned to that person (taskService.createTaskQuery().assignee("manager").list()) and update the assignee to the new one…

hmartim
Champ in-the-making
Champ in-the-making
That would be an interesting way if there was only one case to treat, as the example of the employee's manager. But there are several cases with different logics.

Since these logical, which can be complex, would be encapsulated in the called beans operations, the replay would be simpler than externally treat each event and update the internal structure of the Actitivi database.

Is there a way through the engine api to get the string definition for assignment (assignee or candidateUsers) of a UserTask? So, I could recover through the engine the unfinished tasks, retrieve that string definition of each task (like "ldapService.findManagerForEmployee(10)") and make this run externally.

Thanks,
Hudson.

frederikherema1
Star Contributor
Star Contributor
You can get hold of the TaskDefinition, which contains an assigneeExpression. You can evaluate the assigneeExpression (Expression) with the ExpressionManager, against an VariableScope (eg. DelegateExecution). Not sure how you would handle this outside of activiti-context (when no execution is available)…

Bear in mind, TaskDefinition and it's expressions is all internal stuff so can't be 100% sure of backward compatibility Smiley Wink

@see org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior.TaskDefinition
@see org.activiti.engine.impl.el.ExpressionManager

hmartim
Champ in-the-making
Champ in-the-making
I figured something like this:

Periodically (at night, for example), retrieve unfinished tasks with TaskService.createTaskQuery ().<…>. list()

For each task, retrieve the key of its definition with task.getTaskDefinitionKey()

Retrieve the task definition using the recovered key (How to do it via api?)

For tasks with a dynamic assignment, evaluate the assigneeExpression (Expression) with the ExpressionManager (How to do it via api?) and call the bean to retrieve the user in this new time.

If it was different from today's, update it via api.

This is correct?

Thanks.

frederikherema1
Star Contributor
Star Contributor
That's indeed a way of doing this, without intruding into the engine. Getting the taskDefinition requires casting to impl classes:

ProcessDefinitionEntity procDef  = (ProcessDefinitionEntity) ((ReposityServiceImpl)repositoryService).getDeployedProcessDefinition(processDefinitionId);
tDef = procDef.getTaskDefinition("userTask");

No guarantees on backward compatibility Smiley Wink

hmartim
Champ in-the-making
Champ in-the-making
I'll try this way then.

Thank you for your replies!

jsher
Champ in-the-making
Champ in-the-making
Hi

I would like to add a TaskListener to all tasks without having to require all process designers to specify the listener in xml, ie. a 'standard' task listener which will ensure that some standard behaviour for all user tasks, eg. notify creation of user task instances to various external listening apps/guis/etc

Getting access to the process definitions at runtime (as shown in previous replies) and adding our standard task listener seems like one way to do this, but as this relies on accessing Activiti internals I am wary of going down this route. A couple of questions then..
1. Is there a better way to do this ?
2. If not, how risky is it to rely on these 'internals' from point of view of future compatibility.

Thanks
    James

frederikherema1
Star Contributor
Star Contributor
Try the BPMNListener approach I suggested a while back… see:

http://forums.activiti.org/en/viewtopic.php?f=6&t=1189&p=4839&hilit=ParseListener#p4839

This way you can, on every task that is used in Activiti, add your listeners without having to define them on each and every process.

jsher
Champ in-the-making
Champ in-the-making
That's great -thanks Frederik.

Just to clarify my understanding of how this works… At process deployment time (ProcessRepository.deployProcess) the BPMN parser will invoke parseUserTask() for all registered BpmnParseListener's. The listener adds TaskListener and Activiti persists this along with the process definition. Is this how it goes ?

How to register the listener ? ProcessEngineConfigurationImpl.? - setPreParseListeners, setPostParseListeners, setCustomPreBPMNParseListeners, setCustomPostBPMNParseListeners ?

Regards
    James