1 2 3 Previous Next 30 Replies Latest reply on Oct 1, 2009 1:11 PM by sebastian.s

    Implementing Escalation in jBPM 4.1

    sebastian.s

      Good morning everybody, good morning Ronald. ;)

      In jBPM 3.x escalating tasks was not possible directly but there was a solution described by Boris Lublinsky in his InfoQ article.

      http://www.infoq.com/articles/jBPM-user-interaction-patterns

      Is this (the impossibility) still the case in jBPM 4.1? In case this is true: I know a lot of the approaches described in the article are not valid anymore with jBPM 4.1 but how about the escalation?

      If there is still no escalation in jBPM wouldn't this be an important feature for a process engine?

      Cheers!
      Sebastian

        • 1. Re: Implementing Escalation in jBPM 4.1
          sebastian.s

          Okay, I just went over the specific part of the article again and to me it seems it is possible. It just seems to me that is a bit too much code for a basic BPM-thing as an escaltion is one.

          • 2. Re: Implementing Escalation in jBPM 4.1
            kukeltje

            One day late, and afternoon already since this response required a little digging for me :-)

            In theory you are right, escalating is a basic BPM-thing

            In practical situations howeever, escalation differs from company to company, department to department etc... and if you have a look at http://www.workflowpatterns.com/patterns/resource/detour/wrp28.php you see that even the theoretical people look at it from a very narrow perspective.

            They say jBPM (3.1.4 !!!!) does not support it, that is because they assume businesspeople should be able to to everything, and a BPM 'framework' like jBPM which can do much more than other products gets a '-' rating because sometimes you need java... sigh...

            You can make it as complex as needed like in the article you refer to, but you can also keep it simple and just assigning the current task to someone else on a timeout event.

            The way it is done in the article is valid for jBPM 3 and 4 (ok different interfaces and jpdl changes, but the basics is the same)

            jBPM 4 has a still undocumented feature (it is not even in the dev guide yet) which is based in the PVM. There is the concept of a "task lifecycle" in combination with the accompanying java code.

            But keep in mind, it is not supported. This does not mean it does not work, only that there are no guarantees that it stays 100% as it is, and that I and other users, probably did not customize it much either so support in the forum is also kind of limited.

            What *is* nice about this 'solution' is that jBPM eats its own dogfood (again) by re-using the pvm in yet another way.

            (I think someone could even make a (ws-)Human Task based on this if he/she cares to read 100's of pages)

            • 3. Re: Implementing Escalation in jBPM 4.1
              sebastian.s

              Thanks for this really long answer, Ronald. In my opinion you are right, escalation is a very complex thing and can mean a lot and I appreciate the flexibility of jBPM but maybe we should think of a basic thing to be included with the distro while replacing it with your own implementation is still possible. Enable simple escalations without the need of coding to give people a smooth start.

              To me it is actually about a simple one right now. I would like to assign a task to somebody else or take a transition to a second task assigned to somebody else.

              I managed to use a timer to make the engine take a timeout transition after some time. My question here: If you make the engine take the transition like this is the previous task completed? Or is this the wrong approach and I should just change the assignment of the task in jBPM?

              I am thinking about the first one because business people often model escalations like this: There is a transition to take when the task is completed or a different one is taken on a timer event leading to a task assigned to somebody else.

              If the task was marked completed when the timeout transition was taken wouldn't this be a bit strange for reports on processes because actually the first person did not complete the task but it was marked as completed?

              • 4. Re: Implementing Escalation in jBPM 4.1
                sebastian.s

                Regarding the task lifecyle I have not written anything since I have not yet looked into this.

                • 5. Re: Implementing Escalation in jBPM 4.1
                  kukeltje

                   

                  "The European guy" wrote:
                  I managed to use a timer to make the engine take a timeout transition after some time. My question here: If you make the engine take the transition like this is the previous task completed? Or is this the wrong approach and I should just change the assignment of the task in jBPM?


                  In 3 it is ended (and configurable) in 4 it is not ended (not configurable) but there is a jira issue for this to make it compatible again. Reassignment is also an option, but that is not visible in the processdefinition then.

                  "The European guy" wrote:
                  I am thinking about the first one because business people often model escalations like this: There is a transition to take when the task is completed or a different one is taken on a timer event leading to a task assigned to somebody else.
                  Yes, me to, and this will be visualized also on the GPD once the timeout from BPMN comes into play

                  "The European guy" wrote:
                  If the task was marked completed when the timeout transition was taken wouldn't this be a bit strange for reports on processes because actually the first person did not complete the task but it was marked as completed?


                  That is why the task lifecycle is so interesting since you can add an additional 'state' (not a node but the state of a task ;-))

                  • 6. Re: Implementing Escalation in jBPM 4.1
                    kukeltje

                    oh, in addition, in 4 the tasks remains open, also not what you want I think.

                    • 7. Re: Implementing Escalation in jBPM 4.1
                      sebastian.s

                      Thanks for your interesting answer, Ronald. I think for know I use the timer/transitition approach because I need I want to visualize the escalation in the diagram shown in the console. So it would be necessary to call a completeTask() for the "old task" manually to remove it from the first user's task list.

                      • 8. Re: Implementing Escalation in jBPM 4.1
                        kukeltje

                        Yes I think you do need that. Would be nice if you made a unit test first to test if that really works. I think it does, but not completely sure.

                        • 9. Re: Implementing Escalation in jBPM 4.1
                          sebastian.s

                          I must be doing something wrong. I took the unit tests of the supplied examples as a base (regarding configuration files) which always worked fine for and I created my process and my tests. The problem is that an exception is thrown:

                          12:03:47,093 FIN | [ProcessDefinitionImpl] creating new execution for process 'escalation'
                          12:03:47,109 FIN | [DefaultIdGenerator] generated execution id escalation.1
                          12:03:47,234 FIN | [ExecuteActivity] executing activity(start1)
                          12:03:47,250 FIN | [DefaultIdGenerator] generated execution id escalation.1.timeout_task
                          12:03:47,406 FIN | [ExecutionImpl] created execution[escalation.1.timeout_task]
                          12:03:47,406 FIN | [ScopeInstanceImpl] creating timer on execution[escalation.1.timeout_task]
                          ### EXCEPTION ###########################################
                          12:03:47,625 INF | [DefaultCommandService] exception while executing command org.jbpm.pvm.internal.cmd.StartProcessInstanceInLatestCmd@694f12
                          org.jbpm.api.JbpmException: no org.jbpm.pvm.internal.cal.BusinessCalendar in current environment
                          


                          <process name="escalation" xmlns="http://jbpm.org/4.0/jpdl">
                           <start g="174,36,48,48" name="start1">
                           <transition g="-106,-24" name="to timeout_task" to="timeout_task"/>
                           </start>
                           <task assignee="alex" g="152,168,92,52" name="timeout_task">
                           <transition g="-50,-21" name="timeout" to="escalated">
                           <timer duedate="5 seconds" />
                           </transition>
                           <transition g="-50,-21" name="to task2" to="task2"/>
                           </task>
                           <task assignee="mike" g="352,169,92,52" name="escalated">
                           <transition g="-50,-21" name="to task2" to="task2"/>
                           </task>
                           <task assignee="peter" g="151,305,92,52" name="task2">
                           <transition g="-48,-21" name="to end1" to="end1"/>
                           </task>
                           <end g="176,398,48,48" name="end1"/>
                          </process>
                          


                           public void testTaskEscalaton() {
                           ProcessInstance processInstance = executionService.startProcessInstanceByKey("escalation");
                           String processInstanceId = processInstance.getId();
                           processInstance = executionService.findProcessInstanceById(processInstanceId);
                          
                           List<Task> tasksAlex = taskService.findPersonalTasks("alex");
                          
                           if(tasksAlex.size() == 0) {
                           fail();
                           }
                          
                           Job job = managementService.createJobQuery()
                           .timers()
                           .processInstanceId(processInstance.getId())
                           .uniqueResult();
                          
                           managementService.executeJob(job.getId());
                           processInstance = executionService.findProcessInstanceById(processInstance.getId());
                           assertTrue(processInstance.isActive("escalated"));
                          
                           List<Task> tasksMike = taskService.findPersonalTasks("mike");
                           if(tasksMike.size() == 0) {
                           fail();
                           }
                          
                           tasksAlex = taskService.findPersonalTasks("alex");
                           if(tasksAlex.size() == 1) {
                           taskService.completeTask(tasksAlex.get(0).getId());
                           } else {
                           fail();
                           }
                          
                           }
                          


                          • 10. Re: Implementing Escalation in jBPM 4.1
                            sebastian.s

                            I do not know what exactly is the problem with the BusinessCalendar but I created my process and my unit test within the examples project and the error has gone away. Now back to the actual goal.

                            Please disregard my old post since there were some mistakes and things missing.

                            My process definition looks like this:

                            <process key="escalation" name="escalation" xmlns="http://jbpm.org/4.0/jpdl">
                             <start g="130,8,48,48" name="start1">
                             <transition g="-93,-21" name="to timeout_task" to="timeout_task"/>
                             </start>
                             <task g="106,105,92,52" name="timeout_task" assignee="alex">
                             <transition g="7,-32" name="to escalated" to="escalated">
                             <timer duedate="5 seconds"/>
                             <timer duedate="5 seconds"/>
                             <timer duedate="5 seconds"/>
                             <timer duedate="5 seconds"/>
                             </transition>
                             <transition g="-50,-21" name="to task2" to="task2"/>
                             </task>
                             <task g="303,211,92,52" name="escalated" assignee="mike">
                             <transition g="-50,-21" name="to task2" to="task2"/>
                             </task>
                             <task g="109,256,92,52" name="task2" assignee="peter">
                             <transition g="-48,-21" name="to end1" to="end1"/>
                             </task>
                             <end g="132,367,48,48" name="end1"/>
                            </process>
                            


                            My unit test follows:
                            package org.jbpm.examples.userescalation;
                            import java.util.List;
                            
                            import org.jbpm.api.Execution;
                            import org.jbpm.api.ProcessInstance;
                            import org.jbpm.api.job.Job;
                            import org.jbpm.api.task.Task;
                            import org.jbpm.test.JbpmTestCase;
                            
                            public class EscalationTest extends JbpmTestCase {
                            
                             String deploymentId;
                            
                             protected void setUp() throws Exception {
                             super.setUp();
                            
                             deploymentId = repositoryService.createDeployment()
                             .addResourceFromClasspath("org/jbpm/examples/userescalation/escalation.jpdl.xml")
                             .deploy();
                             }
                            
                             protected void tearDown() throws Exception {
                             repositoryService.deleteDeploymentCascade(deploymentId);
                            
                             super.tearDown();
                             }
                            
                             public void testTaskEscalaton() {
                            
                             ProcessInstance processInstance = executionService.startProcessInstanceByKey("escalation");
                            
                             List<Task> tasksAlex = taskService.findPersonalTasks("alex");
                            
                             // check if Alex's task has been created
                             if(tasksAlex.size() == 0) {
                             fail();
                             }
                            
                             // executing the job which would normally be executed by the JobExecutor
                             Job job = managementService.createJobQuery()
                             .timers()
                             .processInstanceId(processInstance.getId())
                             .uniqueResult();
                            
                             managementService.executeJob(job.getId());
                             processInstance = executionService.findProcessInstanceById(processInstance.getId());
                            
                             // we now should have arrived in the node "escalated"
                             assertTrue(processInstance.isActive("escalated"));
                            
                             // there should be an item in Mike's tasklist now
                             List<Task> tasksMike = taskService.findPersonalTasks("mike");
                             if(tasksMike.size() == 0) {
                             fail();
                             } else {
                             taskService.completeTask(tasksMike.get(0).getId());
                             }
                            
                             // after Mike has completed his task we should have arrived in the node "task2"
                             processInstance = executionService.findProcessInstanceById(processInstance.getId());
                             assertTrue(processInstance.isActive("task2"));
                            
                             // Alex's tasks still exists although it is obsolete now
                             tasksAlex = taskService.findPersonalTasks("alex");
                            
                             // deleting is not possible since this task belongs to an execution
                             //taskService.deleteTask(tasksAlex.get(0).getId(), "obsolete");
                            
                             // so we have to complete it, what is unwanted for BAM
                             taskService.completeTask(tasksAlex.get(0).getId());
                            
                             // ########### but this fails with an exception ########
                            
                             // there shouldn't be any tasks left for alex
                             //tasksAlex = taskService.findPersonalTasks("alex");
                             //assertEquals(0, tasksAlex.size());
                            
                             }
                            
                            }
                            


                            The exception thrown when completeTask() is called:
                            ### EXCEPTION ###########################################
                            16:19:12,140 INF | [DefaultCommandService] exception while executing command org.jbpm.pvm.internal.cmd.CompleteTaskCmd@ff45de
                            org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [org.jbpm.pvm.internal.model.ExecutionImpl#2]
                            


                            Am I doing anything wrong or does this mean you should not put timers on transitions coming from user tasks?

                            • 11. Re: Implementing Escalation in jBPM 4.1
                              kukeltje

                              there was a change in the businesscalendar config afaik between 4.0, and 4.1 (or was it towards 4.2, not fully sure). Did you change versions? If so, search the jira for the related task and see if it is the possible cause.

                              • 12. Re: Implementing Escalation in jBPM 4.1
                                sebastian.s

                                I'll have a look into JIRA and I will verify that I am not mixing up files from different versions. But what about my actual problem (see my last post). How do I get rid of the task which is not needed anymore?

                                • 13. Re: Implementing Escalation in jBPM 4.1
                                  sebastian.s

                                  Full Stacktrace ..

                                  ### EXCEPTION ###########################################
                                  11:00:39,186 INF | [DefaultCommandService] exception while executing command org.jbpm.pvm.internal.cmd.CompleteTaskCmd@1c01ba9
                                  org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [org.jbpm.pvm.internal.model.ExecutionImpl#2]
                                   at org.hibernate.impl.SessionFactoryImpl$2.handleEntityNotFound(SessionFactoryImpl.java:409)
                                   at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:108)
                                   at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:97)
                                   at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:140)
                                   at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
                                   at org.jbpm.pvm.internal.model.ExecutionImpl_$$_javassist_4.getHistoryActivityInstanceDbid(ExecutionImpl_$$_javassist_4.java)
                                   at org.jbpm.pvm.internal.history.events.TaskComplete.process(TaskComplete.java:49)
                                   at org.jbpm.pvm.internal.history.HistorySessionImpl.process(HistorySessionImpl.java:31)
                                   at org.jbpm.pvm.internal.history.HistoryEvent.fire(HistoryEvent.java:61)
                                   at org.jbpm.pvm.internal.task.TaskImpl.historyTaskComplete(TaskImpl.java:305)
                                   at org.jbpm.pvm.internal.task.TaskImpl.complete(TaskImpl.java:190)
                                   at org.jbpm.pvm.internal.task.TaskImpl.complete(TaskImpl.java:186)
                                   at org.jbpm.pvm.internal.cmd.CompleteTaskCmd.execute(CompleteTaskCmd.java:58)
                                   at org.jbpm.pvm.internal.cmd.CompleteTaskCmd.execute(CompleteTaskCmd.java:32)
                                   at org.jbpm.pvm.internal.svc.DefaultCommandService.execute(DefaultCommandService.java:42)
                                   at org.jbpm.pvm.internal.tx.StandardTransactionInterceptor.execute(StandardTransactionInterceptor.java:54)
                                   at org.jbpm.pvm.internal.svc.EnvironmentInterceptor.execute(EnvironmentInterceptor.java:46)
                                   at org.jbpm.pvm.internal.svc.RetryInterceptor.execute(RetryInterceptor.java:55)
                                   at org.jbpm.pvm.internal.svc.TaskServiceImpl.completeTask(TaskServiceImpl.java:88)
                                   at org.jbpm.examples.userescalation.EscalationTest.testTaskEscalaton(EscalationTest.java:70)
                                   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                                   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
                                   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                                   at java.lang.reflect.Method.invoke(Method.java:597)
                                   at junit.framework.TestCase.runTest(TestCase.java:164)
                                   at org.jbpm.test.BaseJbpmTestCase.runTest(BaseJbpmTestCase.java:80)
                                   at junit.framework.TestCase.runBare(TestCase.java:130)
                                   at junit.framework.TestResult$1.protect(TestResult.java:106)
                                   at junit.framework.TestResult.runProtected(TestResult.java:124)
                                   at junit.framework.TestResult.run(TestResult.java:109)
                                   at junit.framework.TestCase.run(TestCase.java:120)
                                   at junit.framework.TestSuite.runTest(TestSuite.java:230)
                                   at junit.framework.TestSuite.run(TestSuite.java:225)
                                   at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
                                   at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
                                   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
                                   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
                                   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
                                   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
                                  ### EXCEPTION ###########################################
                                  11:00:39,186 SEV | [BaseJbpmTestCase]
                                  ### EXCEPTION ###########################################
                                  11:00:39,186 SEV | [BaseJbpmTestCase] TEST THROWS EXCEPTION: No row with the given identifier exists: [org.jbpm.pvm.internal.model.ExecutionImpl#2]
                                  org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [org.jbpm.pvm.internal.model.ExecutionImpl#2]
                                   at org.hibernate.impl.SessionFactoryImpl$2.handleEntityNotFound(SessionFactoryImpl.java:409)
                                   at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:108)
                                   at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:97)
                                   at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:140)
                                   at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
                                   at org.jbpm.pvm.internal.model.ExecutionImpl_$$_javassist_4.getHistoryActivityInstanceDbid(ExecutionImpl_$$_javassist_4.java)
                                   at org.jbpm.pvm.internal.history.events.TaskComplete.process(TaskComplete.java:49)
                                   at org.jbpm.pvm.internal.history.HistorySessionImpl.process(HistorySessionImpl.java:31)
                                   at org.jbpm.pvm.internal.history.HistoryEvent.fire(HistoryEvent.java:61)
                                   at org.jbpm.pvm.internal.task.TaskImpl.historyTaskComplete(TaskImpl.java:305)
                                   at org.jbpm.pvm.internal.task.TaskImpl.complete(TaskImpl.java:190)
                                   at org.jbpm.pvm.internal.task.TaskImpl.complete(TaskImpl.java:186)
                                   at org.jbpm.pvm.internal.cmd.CompleteTaskCmd.execute(CompleteTaskCmd.java:58)
                                   at org.jbpm.pvm.internal.cmd.CompleteTaskCmd.execute(CompleteTaskCmd.java:32)
                                   at org.jbpm.pvm.internal.svc.DefaultCommandService.execute(DefaultCommandService.java:42)
                                   at org.jbpm.pvm.internal.tx.StandardTransactionInterceptor.execute(StandardTransactionInterceptor.java:54)
                                   at org.jbpm.pvm.internal.svc.EnvironmentInterceptor.execute(EnvironmentInterceptor.java:46)
                                   at org.jbpm.pvm.internal.svc.RetryInterceptor.execute(RetryInterceptor.java:55)
                                   at org.jbpm.pvm.internal.svc.TaskServiceImpl.completeTask(TaskServiceImpl.java:88)
                                   at org.jbpm.examples.userescalation.EscalationTest.testTaskEscalaton(EscalationTest.java:70)
                                   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                                   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
                                   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                                   at java.lang.reflect.Method.invoke(Method.java:597)
                                   at junit.framework.TestCase.runTest(TestCase.java:164)
                                   at org.jbpm.test.BaseJbpmTestCase.runTest(BaseJbpmTestCase.java:80)
                                   at junit.framework.TestCase.runBare(TestCase.java:130)
                                   at junit.framework.TestResult$1.protect(TestResult.java:106)
                                   at junit.framework.TestResult.runProtected(TestResult.java:124)
                                   at junit.framework.TestResult.run(TestResult.java:109)
                                   at junit.framework.TestCase.run(TestCase.java:120)
                                   at junit.framework.TestSuite.runTest(TestSuite.java:230)
                                   at junit.framework.TestSuite.run(TestSuite.java:225)
                                   at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
                                   at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
                                   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
                                   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
                                   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
                                   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
                                  ### EXCEPTION ###########################################
                                  11:00:39,186 SEV | [BaseJbpmTestCase]
                                  11:00:39,217 FIN | [DbSessionImpl] deleting history process instance escalation.1
                                  11:00:39,248 FIN | [DbSessionImpl] deleting process instance escalation.1
                                  11:00:39,264 FIN | [DeleteDeploymentCmd] deleting deployment 1
                                  11:00:39,311 FIN | [BaseJbpmTestCase] === ending testTaskEscalaton =============================
                                  


                                  • 14. Re: Implementing Escalation in jBPM 4.1
                                    kukeltje

                                    might be because the process is actually already ended.... Can you check?

                                    1 2 3 Previous Next