cancel
Showing results for 
Search instead for 
Did you mean: 

Custom Execution Listener triggered by VARIABLE_UPDATED event

rhafner
Champ on-the-rise
Champ on-the-rise
Our proprietary workflow engine supports firing a hierarchy of listeners (that are modeled) when a DataObject is updated.

Process
  DataObject-1
  Listener-1
  Listener-2
  Subprocess
    DataObject-2
    Listener-3

For example, when DataObject-2 is updated Listener-3 will run followed by Listener-2. When DataObject-1 is updated Listener-1 will run.

I'm attempting to use an execution listener with a custom type that is triggered by the VARIABLE_UPDATED event in Activiti to support this behavior. Thus far I have been able to get the DataObject-1/Listener-1 case to work but I am having difficulty getting similar behavior to work for the other case involving a subprocess.

The ActivitiEvent that is sent to the VARIABLE_UPDATED listener in the subprocess case contains an execution id that is related to the the subprocesses execution. This execution has an Activity (ACT_ID) that refers to the UserTask that is defined on the subprocess and not the id of the subprocess as defined in the BPMN template. In order to retrieve the execution listeners for the subprocess from the ProcessDefinition I need the id of the subprocess from the template.

Questions:
* Is there a way to access the id of the subprocess as defined in the template from within the listener?
* Are there alternative ways to implement this behavior that we should be investigating?

Here is a code snippet of the VariableUpdated Listener for reference:

public void onEvent(ActivitiEvent activitiEvent)
{
   Execution execution =runtimeService.createExecutionQuery().executionId(activitiEvent.getExecutionId()).singleResult();
   while (null != execution)
   {
     ExecutionEntity executionEntity = (ExecutionEntity)execution;
     if (null != executionEntity.getVariableLocal(Constants.PROCESS_PATH))
     {
       ScopeImpl scope;
       if (executionEntity.getId().equals(executionEntity.getProcessInstanceId()))
       {
         scope = executionEntity.getProcessDefinition();
       }
       else
       {
         // UserTask in subprocess. Need the subprocess.
         scope = executionEntity.getActivity();
       }

       List<ExecutionListener> listeners = scope.getExecutionListeners(message);
        for (ExecutionListener listener : listeners)
        {
           listener.notify(executionEntity);
        }    
        execution = executionEntity.getParent();
   }
}
2 REPLIES 2

trademak
Star Contributor
Star Contributor
Hi Robert,

Did you try to get the parent execution of the current user task execution?

Best regards,

rhafner
Champ on-the-rise
Champ on-the-rise
Hi Tijs,

Yes, it does not help in this case since the parent execution of the user task execution is the process execution and not the subprocess execution. I was surprised at the fact that there isn't a "subprocess" execution in this case. I'm wondering if that is a result of how my test template is defined. I've attached a copy of it. Note there are no UserTasks or Service Tasks in the process. The process simply flows directly into the subprocess.

I was able to make this work in the following way:
1) Override DefaultActivityBehaviorFactory.createSubprocActivityBehavior() method to return a custom class which has a field that stores the id of the subprocess from the template.
1) In the execute method of the custom SubProcessActivityBehavior class set the subprocess id in a local variable.
2) Update the VARIABLE_UPDATED event listener class to find the scope for a subprocess using the local variable and the process definition. For example:
String subprocessDefinitionId = (String)executionEntity.getVariableLocal(Constants.SUBPROCESS_DEFINITION_ID);
scope = executionEntity.getProcessDefinition().findActivity(subprocessDefinitionId);

I'm still testing. But this seems to be working for us.

Is there an alternative approach that wouldn't require us to create a local variable?