cancel
Showing results for 
Search instead for 
Did you mean: 

How to verify user task assignment at runtime?

raj1
Champ in-the-making
Champ in-the-making
I have a Business Process with two user tasks ut1 and ut2 namely. Both usertasks have same candidate group Management. After deploying the process, at runtime, the requirement is to ensure that usertasks ut1 and ut2 are preformed by different users in the Candidate groups Management. For e.g.  if Kermit performs the task ut1, he(Kermit) cannot claim & perform the task ut2 and also ut2 has to be claimed & performed by another user in Candidate group Management.

To achieve this:

I will have to create Task listener for the user task ut2 on the event "assignment", then in the task listener get history of the usertask ut1 and check if the user assigned for task ut2 and the user performed the task ut1 are same.

If they are same then mark the task ut2 as unassigned.

Is this the correct approach?

Please guide me as how to go about and achieve this requirement?
21 REPLIES 21

frederikherema1
Star Contributor
Star Contributor
If you remove the "beans" property, ALL spring beans will be available, and than your listener will no longer be a circular reference… (in case you're using the SpringProcessEngineConfiguration) Not sure if this is a good solution for you, just suggesting Smiley Wink

heymjo
Champ on-the-rise
Champ on-the-rise
i'm having a similar issue with defining a BpmnParseListener. They need to be injected in the (Spring)ProcessEngineConfiguration, but if the parselistener depends on the engine itself i get a nullpointer exception because the engine has not been initialized via the ProcessEngineFactoryBean. If i wouldn't use factorybeans i would get circular references instead.


  <bean id="config" class="org.activiti.spring.SpringProcessEngineConfiguration">
    <property name="customPreBPMNParseListeners">
      <util:list>
        <ref bean="userGroupsCheckParseListener"/>
      </util:list>
    </property>
  </bean>

  <bean id="userGroupsCheckParseListener" class="my.UserGroupsCheckParseListener">
    <property name="userGroupsCheckTaskListener">
      <bean class="my.UserGroupsCheckTaskListener"/>
    </property>
  </bean>

and the tasklistener needs the RepositoryService to lookup a ProcessDefinitionEntity.

The springprocessengineconfiguration could add value here maybe by scanning for @PreParseListener, @PostParseListener annotations and add them dynamically. Then again i don't know how often this feature will get used so is there much point ?

Also, doing ProcessEngineConfiguration.getPreParseListeners().add(myparselistener) does not work because the processengine is already initialized. so we cannot dynamically add a parselistener after the processengine has been created, that is a bit suprising but only slightly inconvenient.

frederikherema1
Star Contributor
Star Contributor
Once the engine is created, the ProcessEngineConfiguration shouldn't be altered, so adding parselisteners indeed won't do anything…

Don't see much advantage in creating annotations for that, since it's not commonly used…

heymjo
Champ on-the-rise
Champ on-the-rise
Once the engine is created, the ProcessEngineConfiguration shouldn't be altered
yet adding custom groupmanager and usermanager implementations via the SpringProcessEngineConfiguration requires us to do exactly that, and that's even the "official" way of doing it AFAIK 🙂

frederikherema1
Star Contributor
Star Contributor
The official way? Smiley Wink Should be added before the buildEngine() is called (the engine is created). In spring, the factory-bean calls the buildEngine method. Adding stuff to it is offcourse possible, but not all configuration is updatable (like the bpmn-listeners, since they are added to the BPMNParser only once, when process-engine is built).

mahavirj
Champ in-the-making
Champ in-the-making
I just tried autowiring the taskService into the listener to perform some task inquiries in the listener and it works ok.

However, as per this discussion, should we not be using engine APIs (within listeners) even for inquiries?  This can be quite a limitation:

When you use the API from within a taskListener, you actually execute a new command from within a running command. If the datasource is transaction-aware (in case of spring), you'll use the same connection as the command-context of the calling command. If not, a fresh one is used. In both cases, all changes done in the first command, aren't visible to the second command, since the changes aren't flushed yet

When the datasource is transaction-aware, the same connection is used as the calling command. If the connection is the same across contexts, why can't other changes changes in the context be shared?  I mean, this sounds like there is no read-consistency within the same transaction.   Maybe flushing those changes in the parent context to the sqlconnection without committing them would solve this? The alternative appears to be to use activiti internals (as frederikheremans points out earlier in this thread) and that's not a good option.

frederikherema1
Star Contributor
Star Contributor
As I stated in another thread (somewhere on the forum here, can't remember where Smiley Wink), the changes from a single command are only flushed to the SQLConnection at the end of the command… So even when datasource is transaction-aware (and returning same connection) the changes still won't be visible in eg. a query launched from an executing tasklistener, since they aren't flushed yet.

We can't just commit the changes before, this is done for optimization (creates, updates and deletes are optimized to limit the number of DB-queries).

So you CAN off course use the API from "within" (if you're using spring, the datasource is always transaction aware) as long as you don't WRITE anything related to the process the parent context is operating, this will cause optimistic lock exception and rollback when touching the same entity.

Any way, any input is welcome. Since I answered the API/Context question many times, this indicates this is a frequently used feature and needs to be tackled.

heymjo
Champ on-the-rise
Champ on-the-rise
I think as a first thing it should be made easier to access the engine services through the listener interface, by providing a reference to them in the callback method signature. Then with javadoc you can mark methods as safe or not, or you handle this in code even if possible.

raki1497
Champ in-the-making
Champ in-the-making

Am very new to this , can you please explain in detail steps for how to achieve this .

1. I cliked on task listner of userTask B ..... and event on Create and i gave task listner class(which is showing error that class not found exception  " my.FourEyesTaskListener"

2. Where to write this class and the below code  ... and how to get task A assigne here (String userId = …             Is it some thing like task.getAssignee():smileywink: please correct me if am wrong.

public class FourEyesTaskListener implements TaskListener {

  // injected by activiti
  private String fourEyesTask;

  // see http://www.activiti.org/javadocs/org/activiti/engine/delegate/DelegateTask.html
  public void notify(DelegateTask delegateTask) {
    // find out the user id that executed the four eyes task 
    String userId = ….
    //
    delegateTask.deleteCandidateUser(userId);
  }
}

Please help me with some screenshot example.

mdtabrezmca
Star Contributor
Star Contributor

Hi,

   Please have a look at this blog post if you are using APS enterprise.

https://community.alfresco.com/community/bpm/blog/2016/11/16/activiti-enterprise-developer-series-pr... 

  If you are using activiti 6 and want to accomplish the custom task assignement please use custom taskk listeners

Activiti User Guide 

Note: you can use the above code by just annotating it with @componenet steroetype from spring so that you will not get class not found exception.

I hope this much info is useful for you.