1 2 Previous Next 21 Replies Latest reply: Nov 22, 2010 3:52 AM by LX T RSS

EventListener questions

Sebastian Schneider Master

Good evening,

I have got a question regarding jBPM's behaviour. Assuming I have a transition coming from a user task and I put an EventListener on this transition: When the transition fires and the EventListener is notified and executes is the task already to be found as a HistoryTask? I am asking because I would like to access the task object to retrieve some information.

My second question: Is there a way to obtain a reference to the HistoryService or TaskService? Or is there a different way to access the task object?

I would like to retrieve the task's creation date.

Thanks for any suggestions.

  • 1. Re: EventListener questions
    Joram Barrez Master

    Sebastion,

    I have got a question regarding jBPM's behaviour. Assuming I have a transition coming from a user task and I put an EventListener on this transition: When the transition fires and the EventListener is notified and executes is the task already to be found as a HistoryTask? I am asking because I would like to access the task object to retrieve some information.


    Conceptually I would say yes: it is only when the task is completed (and history is saved) that the transition is taken. Since the same Hibernate session is used when taking the transition, it could be not yet persisted but you'll find it anyway through the session.

    However, I did not test this, the only thing you can try is test it :-)

    My second question: Is there a way to obtain a reference to the HistoryService or TaskService? Or is there a different way to access the task object?


    The easiest would be to inject the ProcessEngine or to store the ProcessEngine somewhere application-wide to retrieve the services.

  • 2. Re: EventListener questions
    Sebastian Schneider Master

    Hello Joram,

    thank you very much for your explaination. I guess I'll try to inject the ProcessEngine.

    Regards
    Sebastian

  • 3. Re: EventListener questions
    Sebastian Schneider Master

    This works for me. Note that I am using the process engine built by the default configuration which is stored in a static field in Configuration.

    public class ApprovalListener implements EventListener {
    
     private static final long serialVersionUID = 1L;
    
     @Override
     public void notify(EventListenerExecution execution) throws Exception {
     ProcessEngine processEngine = Configuration.getProcessEngine();
     HistoryService historyService = processEngine.getHistoryService();
     HistoryTask task = HistoryService.createHistoryTaskQuery().executionId(execution.getId()).uniqueResult();
    
     // now I can retrieve the information I wanted ..
     task.getAssignee()
     task.getCreateTime()
     ..
     }
    
    }
    


  • 4. Re: EventListener questions
    Sebastian Schneider Master

    I haven't found a way to achieve this using the HistoyTaskQuery. I would like to retrieve the task where the transition originates from.

    HistoryTask task = HistoryService.createHistoryTaskQuery().executionId(execution.getId()).unique
    


    worked fine for me as long as I just had one task in the process definition. Am I missing anything or is this really as tricky as it seems to be to retrieve the previous task?

  • 5. Re: EventListener questions
    Joram Barrez Master

    Getting the previous task is indeed tricky. Because it depends on what you call 'previous'. The previous one in the process, transition-wise (as you state). Or is it the previous task that has been done by the same assignee (easy to retrieve) in potentially some parallel path?

    For me it is the latter, but for you obviously it isn't.

    A easy workaround is using an eventlistener and storing the 'previous task' as a process var ... (or only the id of the historyTask) ... albeit this is just a very quick workaround.

  • 6. Re: EventListener questions
    Sebastian Schneider Master

    Of course you're right and one could easily argue about the definition and yes I am talking about the last task in an transition-wise way.

    I have to say that I don't understand the workaround you have proposed. I've been re-thinking this and it came to my mind that thinking in a transition-wise way actually I would have to get the activitiy the transition originates from and than retrieve the corresponding task since it's an activity of type task, right?

    Could you try to explain your proposition a bit more? Thank you very much, Joram.

  • 7. Re: EventListener questions
    Joram Barrez Master

     

    I have to say that I don't understand the workaround you have proposed. I've been re-thinking this and it came to my mind that thinking in a transition-wise way actually I would have to get the activitiy the transition originates from and than retrieve the corresponding task since it's an activity of type task, right?


    Yes, you're correct. But this doesn't simplify the problem

    Could you try to explain your proposition a bit more?


    I was thinking something simple: attach an eventlistener to the task-end event. When the eventlistener is called, it simply sets the current task name/id/whatever as a process variable.

    In the next task you can use this variable.

    Like a said, this is a quick hack-aroo solution which can work until we enlarge the history event capabilities

  • 8. Re: EventListener questions
    Sebastian Schneider Master

    Thanks for clarifying this. The review of the JIRA issues regarding the history API is taking place during the next days, right? Maybe this could also be taken into account.

  • 9. Re: EventListener questions
    Sebastian Schneider Master

    But how to access the current task-object from within the EventListener firing on the task-end event? I just have access to execution which is of type EventListenerExecution.

  • 10. Re: EventListener questions
    Sebastian Schneider Master

    I decided to use the start event because so I can use a TaskQuery instead of HistoryTaskQuery. I just want to gain access to the properties of the task the transition originates from.

    process definition:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <process name="process" xmlns="http://jbpm.org/4.0/jpdl" key="process" version="1">
     <start name="start1" g="74,95,48,48">
     <transition name="to task1" to="task1" g="1,-23"/>
     </start>
     <end name="end1" g="73,270,48,48"/>
     <task name="task1" g="215,141,92,52" assignee="alex">
     <on event="start">
     <event-listener class="listeners.TaskEventListener" />
     </on>
     <transition name="to task2" to="task2" g="-50,-21"/>
     </task>
     <task name="task2" g="214,270,92,52" assignee="mike">
     <transition name="to end1" to="end1" g="-48,-21"/>
     </task>
    </process>
    


    EventListener:
    package listeners;
    
    import java.util.Set;
    
    import org.jbpm.api.Configuration;
    import org.jbpm.api.ProcessEngine;
    import org.jbpm.api.TaskService;
    import org.jbpm.api.listener.EventListener;
    import org.jbpm.api.listener.EventListenerExecution;
    import org.jbpm.api.task.Task;
    
    public class TaskEventListener implements EventListener {
    
     private static final long serialVersionUID = 1L;
     private ProcessEngine processEngine;
     private TaskService taskService;
    
     public TaskEventListener() {
     processEngine = Configuration.getProcessEngine();
     taskService = processEngine.getTaskService();
     }
    
     @Override
     public void notify(EventListenerExecution execution) throws Exception {
     Set<String> activities = execution.findActiveActivityNames();
     String activityName = activities.iterator().next();
     // this works: task1 (= the name of the activity is shown)
     System.out.println(activityName);
     // this does not work, getting null here
     Task task = taskService.createTaskQuery().activityName(activityName).uniqueResult();
     System.out.println(task);
     }
    
    }
    


    Unit test:
    package tests;
    
    
    import java.util.List;
    
    import org.jbpm.api.Configuration;
    import org.jbpm.api.ProcessEngine;
    import org.jbpm.api.ProcessInstance;
    import org.jbpm.api.task.Task;
    import org.jbpm.test.JbpmTestCase;
    
    public class TaskEventListenerTest extends JbpmTestCase {
    
     String deploymentId;
    
     protected void setUp() throws Exception {
     super.setUp();
     ProcessEngine engine = Configuration.getProcessEngine();
     deploymentId = engine.getRepositoryService().createDeployment().addResourceFromClasspath("process.jpdl.xml").deploy();
     }
    
     public void testTaskEventListener() {
     ProcessInstance processInstance = executionService.startProcessInstanceByKey("process");
     List<Task> tasks = taskService.findPersonalTasks("alex");
     taskService.completeTask(tasks.get(0).getId());
     tasks = taskService.findPersonalTasks("mike");
     taskService.completeTask(tasks.get(0).getId());
     }
    
     protected void tearDown() throws Exception {
     repositoryService.deleteDeploymentCascade(deploymentId);
     super.tearDown();
     }
    
    }
    


    Why is the task not found using the TaskQuery?

    My second question would be: Why is there a citeria called processInstanceId although as far as I recall the class Task has a member variable called executionId and so is associated with its execution and not with its process instance, right?

    http://docs.jboss.com/jbpm/v4/javadocs/org/jbpm/api/task/Task.html

    Anyway the activityName is a better criteria because I might have several tasks active at the same time.

  • 11. Re: EventListener questions
    Ronald van Kuijk Master

    have you tried running this in debug mode? And e.g. log the hibernate queries? Could be that something is not persisted yet.

    I noticed the processInstanceId vs executionId to once in a different place. Has been some renaming long ago, maybe these slipped through.

  • 12. Re: EventListener questions
    Sebastian Schneider Master

    I just tried it. I put a breakpoint and used the HSQL's DatabaseManager to have a look at the database. There is no task persisted yet.

    However I could not find a statement "INSERT INTO .. " for the task table in the Hibernate debug output before my query for the task. I put an additional breakpoint after the EventListener's notify()-method is completed and then the task is found in the database.

    So it seems that when the EventListener is notified of the activity's start the task has not been created yet although the activity is already the active one in the execution.

    Hibernate queries are hard to log in a readable way. I can still post them but if you need them you could easily reproduce them with the supplied unit test.

    I've got 2 questions in mind:

    How can I achieve the thing I'm aiming for? Should I change to the activity's end event? But then I would need to use a custom Hibernate Query since I have no criteria to be used for the HistoryTaskQuery.

    And is this a bug or just a specific behaviour of jBPM? An unwanted or wanted one? If this is unwanted and the task should to be found already in the task could this behaviour be changed?

  • 13. Re: EventListener questions
    Joram Barrez Master

    @Sebastian: I'm not sure if this is the intended behaviour. Can you create an issue with your process + unit test and assign it to me? This way I can pick it up later.

  • 14. Re: EventListener questions
    Sebastian Schneider Master

    Hello Joram,

    I created a task and I attached the files for the test case. I cannot assign tasks or bugs to you since I haven't got the permission to do this. So you have to do this:

    https://jira.jboss.org/jira/browse/JBPM-2644

    By accident I uploaded the files to the wrong issue at first. Can you please delete the attached files here?

    https://jira.jboss.org/jira/browse/JBPM-2643

    Thank you.

    P.S.: Have you read my message for you on the mailing list?

1 2 Previous Next