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