8 Replies Latest reply on Jan 19, 2010 2:48 PM by Andre Muniz

    NullPointerException on Assignment-Handler

    Andre Muniz Newbie

      Hi!

       

      On the following test process when the execution reaches task3 JBPM 4.3 throws a null pointer exception.

       

      <?xml version="1.0" encoding="UTF-8"?>
      <process description="Test" key="testProcess" name="Test Process" xmlns="http://jbpm.org/4.3/jpdl">
         <start g="67,236,48,48" name="start1">
            <transition g="-43,-18" name="to fork1" to="fork1"/>
         </start>
         <task g="255,144,92,52" name="task1" candidate-groups="firstGroup">
            <assignment-handler class="com.test.AutoAssignment"/>
            <transition g="-41,-18" name="to join1" to="join1"/>
         </task>
         <task g="258,334,92,52" name="task2" candidate-groups="secondGroup">
            <assignment-handler class="com.test.AutoAssignment"/>
            <transition g="-41,-18" name="to join1" to="join1"/>
         </task>
         <task g="515,228,92,52" name="task3" candidate-groups="thirdGroup">
            <assignment-handler class="com.test.AutoAssignment"/>
            <transition g="-42,-18" name="to end1" to="end1"/>
         </task>
         <end g="676,232,48,48" name="end1"/>
         <fork g="172,236,48,48" name="fork1">
            <transition g="-44,-18" name="to task1" to="task1"/>
            <transition g="-44,-18" name="to task2" to="task2"/>
         </fork>
         <join g="385,233,48,48" name="join1">
            <transition g="-44,-18" name="to task3" to="task3"/>
         </join>
      </process>
      

       

      Error Below:

      java.lang.NullPointerException
           at org.jbpm.pvm.internal.wire.usercode.UserCodeReference.getProcessDefinition(UserCodeReference.java:75)
           at org.jbpm.pvm.internal.wire.usercode.UserCodeReference.getObject(UserCodeReference.java:60)
           at org.jbpm.pvm.internal.wire.usercode.UserCodeReference.getObject(UserCodeReference.java:51)
           at org.jbpm.pvm.internal.model.ExecutionImpl.initializeAssignments(ExecutionImpl.java:759)
           at org.jbpm.jpdl.internal.activity.TaskActivity.execute(TaskActivity.java:95)
           at org.jbpm.jpdl.internal.activity.TaskActivity.execute(TaskActivity.java:58)
           at org.jbpm.pvm.internal.model.op.ExecuteActivity.perform(ExecuteActivity.java:60)
           at org.jbpm.pvm.internal.model.ExecutionImpl.performAtomicOperationSync(ExecutionImpl.java:656)
           at org.jbpm.pvm.internal.model.ExecutionImpl.fire(ExecutionImpl.java:566)
           at org.jbpm.pvm.internal.model.ExecutionImpl.take(ExecutionImpl.java:472)
           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 org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
           at org.jbpm.pvm.internal.model.ExecutionImpl$$EnhancerByCGLIB$$3b9689da.take(<generated>)
           at org.jbpm.jpdl.internal.activity.JoinActivity.execute(JoinActivity.java:93)
           at org.jbpm.jpdl.internal.activity.JoinActivity.execute(JoinActivity.java:49)
           at org.jbpm.pvm.internal.model.op.ExecuteActivity.perform(ExecuteActivity.java:60)
           at org.jbpm.pvm.internal.model.ExecutionImpl.performAtomicOperationSync(ExecutionImpl.java:656)
           at org.jbpm.pvm.internal.model.ExecutionImpl.performAtomicOperation(ExecutionImpl.java:616)
           at org.jbpm.pvm.internal.model.ExecutionImpl.signal(ExecutionImpl.java:417)
           at org.jbpm.pvm.internal.model.ExecutionImpl.signal(ExecutionImpl.java:403)
           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 org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
           at org.jbpm.pvm.internal.model.ExecutionImpl$$EnhancerByCGLIB$$3b9689da.signal(<generated>)
           at org.jbpm.pvm.internal.task.TaskImpl.complete(TaskImpl.java:194)
           at org.jbpm.pvm.internal.task.TaskImpl.complete(TaskImpl.java:186)
           at org.jbpm.pvm.internal.cmd.CompleteTaskCmd.execute(CompleteTaskCmd.java:67)
           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.executeInNewEnvironment(EnvironmentInterceptor.java:53)
           at org.jbpm.pvm.internal.svc.EnvironmentInterceptor.execute(EnvironmentInterceptor.java:40)
           at org.jbpm.pvm.internal.svc.RetryInterceptor.execute(RetryInterceptor.java:55)
           at org.jbpm.pvm.internal.svc.SkipInterceptor.execute(SkipInterceptor.java:43)
           at org.jbpm.pvm.internal.svc.TaskServiceImpl.completeTask(TaskServiceImpl.java:88)
           at com.coral.jbpm.moveOut.MoveOutProcess.completeTask(MoveOutProcess.java:114)
           at com.coral.web.action.process.ProcessInboxAction.completeTask(ProcessInboxAction.java:96)
           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 org.apache.struts.actions.DispatchAction.dispatchMethod(DispatchAction.java:270)
           at org.apache.struts.actions.DispatchAction.execute(DispatchAction.java:187)
           at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:431)
           at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:236)
           at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1196)
           at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432)
           at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
           at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
           at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:269)
           at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
           at com.coral.web.filter.HibernateFilter.doFilter(HibernateFilter.java:79)
           at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
           at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
           at com.coral.web.filter.GZIPFilter.doFilter(GZIPFilter.java:21)
           at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
           at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
           at org.displaytag.filter.ResponseOverrideFilter.doFilter(ResponseOverrideFilter.java:125)
           at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
           at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
           at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
           at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:174)
           at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433)
           at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
           at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
           at org.apache.catalina.authenticator.SingleSignOn.invoke(SingleSignOn.java:373)
           at org.josso.tc55.agent.SSOAgentValve.invoke(SSOAgentValve.java:541)
           at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
           at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:174)
           at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:874)
           at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
           at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
           at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
           at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)
           at java.lang.Thread.run(Thread.java:619)
      

       

      If I take the assignment-handler out it works, which makes me think that's the problem, but if I put it back in the debugger doesn't even get into the class attached below:

       

      package com.test;
      
      import java.util.HashMap;
      import java.util.List;
      import java.util.Map;
      import java.util.Set;
      
      import org.jbpm.api.Configuration;
      import org.jbpm.api.ProcessEngine;
      import org.jbpm.api.TaskService;
      import org.jbpm.api.model.OpenExecution;
      import org.jbpm.api.task.Assignable;
      import org.jbpm.api.task.AssignmentHandler;
      import org.jbpm.api.task.Participation;
      import org.jbpm.api.task.Task;
      
      public class AutoAssignment implements AssignmentHandler {
      
          /**
           * Auto-claim the task to the default user.
           * @param assignable assignable object
           * @param execution execution object
           * @throws Exception exception
           */
          @Override
          public void assign(Assignable assignable, OpenExecution execution) throws Exception {
      
              // Default users (group --> user mapping)
              Map < String, String > defaultUsers = new HashMap < String, String >();
              defaultUsers.put("firstGroup", "firstUser");
              defaultUsers.put("secondGroup", "secondUser");
              defaultUsers.put("thirdGroup", "thirdUser");
      
              // Engine and task service
              ProcessEngine processEngine = new Configuration().buildProcessEngine();
              TaskService taskService = processEngine.getTaskService();
      
              // Loads the active activities
              Set < String > activities = execution.findActiveActivityNames();
      
              // Iterates the activities
              for (String activity : activities) {
      
                  // Loads the tasks according to the process instance and activity name
                  List < Task > tasks =
                          taskService.createTaskQuery().activityName(activity).processInstanceId(
                              execution.getProcessInstance().getId()).list();
      
                  // Iterates the tasks
                  for (Task task : tasks) {
      
                      // Compares the task name to the activity name
                      // If the task name matches the activity name, loads the candidate-group and assigns the default user
                      if (task.getName().equals(activity)) {
      
                          // Loads the tasks candidate groups (in our process we have just one group)
                          List < Participation > groups = taskService.getTaskParticipations(task.getId());
      
                          // If the groups collection is not empty, loads the default user and sets in the task
                          if (!groups.isEmpty()) {
                              assignable.setAssignee(defaultUsers.get(groups.get(0).getGroupId()));
                          }
                      }
                  }
              }
          }
      }
      
      

      As another unexpected result from my testing, if I replace task3 by a fork and 2 tasks, both with assignment-handlers, the execution flows normally:

       

      <?xml version="1.0" encoding="UTF-8"?>
      
      <process description="Test" key="testProcess" name="Test Process" xmlns="http://jbpm.org/4.3/jpdl">
         <start g="67,236,48,48" name="start1">
            <transition g="-43,-18" name="to fork1" to="fork1"/>
         </start>
         <task candidate-groups="firstGroup" g="255,144,92,52" name="task1">
            <assignment-handler class="com.test.AutoAssignment"/>
            <transition g="-41,-18" name="to join1" to="join1"/>
         </task>
         <task candidate-groups="secondGroup" g="258,334,92,52" name="task2">
            <assignment-handler class="com.test.AutoAssignment"/>
            <transition g="-41,-18" name="to join1" to="join1"/>
         </task>
         <end g="858,229,48,48" name="end1"/>
         <fork g="172,236,48,48" name="fork1">
            <transition g="-44,-18" name="to task1" to="task1"/>
            <transition g="-44,-18" name="to task2" to="task2"/>
         </fork>
         <join g="385,233,48,48" name="join1">
            <transition name="to fork2" to="fork2" g="-43,-18"/>
         </join>
         <fork name="fork2" g="506,234,48,48">
            <transition name="to task3" to="task3" g="-44,-18"/>
            <transition name="to task4" to="task4" g="-44,-18"/>
         </fork>
         <task name="task3" g="593,136,92,52">
            <assignment-handler class="com.test.AutoAssignment"/>
            <transition name="to join2" to="join2" g="-41,-18"/>
         </task>
         <task name="task4" g="603,324,92,52">
            <assignment-handler class="com.test.AutoAssignment"/>
            <transition name="to join2" to="join2" g="-41,-18"/>
         </task>
         <join name="join2" g="732,232,48,48">
            <transition name="to end1" to="end1" g="-42,-18"/>
         </join>
      
      </process>
      

       

      Did anyone ever experienced a similar problem or has any idea of what might be happening? Thanks!

        • 1. Re: NullPointerException on Assignment-Handler
          Ronald van Kuijk Master
          do you have a unit test with this? Preferable all embedded in one file (not zip, but one java class, so assignmenthandler as innerclass and processdefinition as string.
          • 2. Re: NullPointerException on Assignment-Handler
            Andre Muniz Newbie

            Hi Ronald!

             

            Here is the unit test.

             

            package test;
            
            import java.util.HashMap;
            import java.util.List;
            import java.util.Map;
            import java.util.Set;
            
            import org.jbpm.api.Configuration;
            import org.jbpm.api.ProcessEngine;
            import org.jbpm.api.ProcessInstance;
            import org.jbpm.api.TaskService;
            import org.jbpm.api.model.OpenExecution;
            import org.jbpm.api.task.Assignable;
            import org.jbpm.api.task.AssignmentHandler;
            import org.jbpm.api.task.Participation;
            import org.jbpm.api.task.Task;
            import org.jbpm.test.JbpmTestCase;
            
            public class ProcessTest extends JbpmTestCase {
            
                /** Deployment id. */
                String deploymentId;
            
                /**
                 * Set up.
                 * @throws Exception exception
                 */
                protected void setUp() throws Exception {
                    super.setUp();
            
                    // XML definition
                    StringBuilder jpdl = new StringBuilder();
                    jpdl.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
                    jpdl.append("<process key=\"testProcess\" name=\"Test Process\" xmlns=\"http://jbpm.org/4.3/jpdl\">");
                    jpdl.append("  <start g=\"67,236,48,48\" name=\"start1\">");
                    jpdl.append("    <transition g=\"-43,-18\" name=\"to fork1\" to=\"fork1\"/>");
                    jpdl.append("  </start>");
                    jpdl.append("  <task g=\"255,144,92,52\" name=\"task1\" candidate-groups=\"firstGroup\">");
                    jpdl.append("    <assignment-handler class=\"test.ProcessTest$AutoAssignment\"/>");
                    jpdl.append("    <transition g=\"-41,-18\" name=\"to join1\" to=\"join1\"/>");
                    jpdl.append("  </task>");
                    jpdl.append("  <task g=\"258,334,92,52\" name=\"task2\" candidate-groups=\"secondGroup\">");
                    jpdl.append("    <assignment-handler class=\"test.ProcessTest$AutoAssignment\"/>");
                    jpdl.append("    <transition g=\"-41,-18\" name=\"to join1\" to=\"join1\"/>");
                    jpdl.append("  </task>");
                    jpdl.append("  <task g=\"515,228,92,52\" name=\"task3\" candidate-groups=\"thirdGroup\">");
                    jpdl.append("    <assignment-handler class=\"test.ProcessTest$AutoAssignment\"/>");
                    jpdl.append("    <transition g=\"-42,-18\" name=\"to end1\" to=\"end1\"/>");
                    jpdl.append("  </task>");
                    jpdl.append("  <end g=\"676,232,48,48\" name=\"end1\"/>");
                    jpdl.append("  <fork g=\"172,236,48,48\" name=\"fork1\">");
                    jpdl.append("    <transition g=\"-44,-18\" name=\"to task1\" to=\"task1\"/>");
                    jpdl.append("    <transition g=\"-44,-18\" name=\"to task2\" to=\"task2\"/>");
                    jpdl.append("  </fork>");
                    jpdl.append("  <join g=\"385,233,48,48\" name=\"join1\">");
                    jpdl.append("    <transition g=\"-44,-18\" name=\"to task3\" to=\"task3\"/>");
                    jpdl.append("  </join>");
                    jpdl.append("</process>");
            
                    // Deploys the process
                    deploymentId =
                            repositoryService.createDeployment().addResourceFromString("testProcess.jpdl.xml", jpdl.toString())
                                    .deploy();
                }
            
                /**
                 * Tear down.
                 * @throws Exception exception
                 */
                protected void tearDown() throws Exception {
                    repositoryService.deleteDeploymentCascade(deploymentId);
                    super.tearDown();
                }
            
                /**
                 * Tests the process.
                 */
                public void testProcess() {
            
                    // Starts a new process instance and gets the instance id
                    ProcessInstance processInstance = executionService.startProcessInstanceByKey("testProcess");
                    String pid = processInstance.getId();
            
                    // Gets the tasks auto-assigned for the first user and completes the task
                    List < Task > taskList = taskService.findPersonalTasks("firstUser");
                    assertEquals(1, taskList.size());
                    Task task = taskList.get(0);
                    taskService.completeTask(task.getId());
            
                    // Gets the tasks auto-assigned for the second user and completes the task
                    taskList = taskService.findPersonalTasks("secondUser");
                    assertEquals(1, taskList.size());
                    task = taskList.get(0);
                    taskService.completeTask(task.getId());
            
                    // Gets the tasks auto-assigned for the second user and completes the task
                    taskList = taskService.findPersonalTasks("thirdUser");
                    assertEquals(1, taskList.size());
                    task = taskList.get(0);
                    taskService.completeTask(task.getId());
            
                    // Tries to load the instance and checks if it was finished
                    processInstance = executionService.findProcessInstanceById(pid);
                    assertNull(processInstance);
                }
            
                /**
                 * Auto assignment class.
                 */
                public static class AutoAssignment implements AssignmentHandler {
            
                    /** Serial version ID. */
                    private static final long serialVersionUID = 9063679883107908899L;
            
                    /**
                     * Auto-claim the task to the default user.
                     * @param assignable assignable object
                     * @param execution execution object
                     * @throws Exception exception
                     */
                    @Override
                    public void assign(Assignable assignable, OpenExecution execution) throws Exception {
            
                        // Default users (group --> user mapping)
                        Map < String, String > defaultUsers = new HashMap < String, String >();
                        defaultUsers.put("firstGroup", "firstUser");
                        defaultUsers.put("secondGroup", "secondUser");
                        defaultUsers.put("thirdGroup", "thirdUser");
            
                        // Engine and task service
                        ProcessEngine processEngine = new Configuration().buildProcessEngine();
                        TaskService taskService = processEngine.getTaskService();
            
                        // Loads the active activities
                        Set < String > activities = execution.findActiveActivityNames();
            
                        // Iterates the activities
                        for (String activity : activities) {
            
                            // Loads the tasks according to the process instance and activity name
                            List < Task > tasks =
                                    taskService.createTaskQuery().activityName(activity).processInstanceId(
                                        execution.getProcessInstance().getId()).list();
            
                            // Iterates the tasks
                            for (Task task : tasks) {
            
                                // Compares the task name to the activity name
                                // If the task name matches the activity name, loads the candidate-group and assigns the default user
                                if (task.getName().equals(activity)) {
            
                                    // Loads the tasks candidate groups (in our process we have just one group)
                                    List < Participation > groups = taskService.getTaskParticipations(task.getId());
            
                                    // If the groups collection is not empty, loads the default user and sets in the task
                                    if (!groups.isEmpty()) {
                                        assignable.setAssignee(defaultUsers.get(groups.get(0).getGroupId()));
                                    }
                                }
                            }
                        }
                    }
                }
            }
            
            • 3. Re: NullPointerException on Assignment-Handler
              Gert Leenders Newbie

              The verry same problem occured in my program which uses JBPM 4.2. Just re-installed JBPM 4.0 and everything works fine now (except for the multiplicity )

               

              Regards,

              Gert

              1 of 1 people found this helpful
              • 4. Re: NullPointerException on Assignment-Handler
                Santanu Saraswati Novice
                Quick note on multiplicity in 4.0 - it was a silly typo that creates that problem. The multiplicity - string is harcoded in JoinBinding. The spelling was wrong. The hardcoded string is "multiplicicty". If use the same string in your jpdl, things will work. This is fixed in later versions.
                • 5. Re: NullPointerException on Assignment-Handler
                  Andre Muniz Newbie

                  Hey Ronald,

                   

                  Don't know if you had a chance to look at the unit test. We are really puzzled with this behavior, please let us know if you have any ideas of what might be happening.

                   

                  Thanks!

                  • 6. Re: NullPointerException on Assignment-Handler
                    Ronald van Kuijk Master
                    Will be trying something tonight if I feel up to it (sinusitis)
                    1 of 1 people found this helpful
                    • 7. Re: NullPointerException on Assignment-Handler
                      Ronald van Kuijk Master

                      Wow... sometimes I even impress myself with what I can achieve.... I got even deeper in the PVM then I did before and even at that level it is clearly written.

                       

                      For one reason I do not know yet, the processDefinition is null in the execution where the task3 is to be created. In this case, the initialization of the assignmenthandler fails.

                       

                      Changing

                       

                       

                          UserCodeReference assignmentHandlerReference = assignableDefinition.getAssignmentHandlerReference();
                          if (assignmentHandlerReference!=null) {
                            AssignmentHandler assignmentHandler = (AssignmentHandler) assignmentHandlerReference.getObject(processDefinition);
                      
                      

                       

                       

                      to

                       

                          UserCodeReference assignmentHandlerReference = assignableDefinition.getAssignmentHandlerReference();
                          if (assignmentHandlerReference!=null) {
                            // FIXME Find out why processdefinition is null in at this time....
                            if (processDefinition == null) {
                                processDefinition = getProcessDefinition();
                            }
                            AssignmentHandler assignmentHandler = (AssignmentHandler) assignmentHandlerReference.getObject(processDefinition);
                      
                      

                       

                       

                      in ExecutionImpl#initializeAssignments Makes the test work. Still have to find out why the processdefinition is null, but that is maybe for the others to find out (I'll file a jira issue for this)

                       

                      btw, Your the code in your assignment class is probably not scaling very well. Have you noticed that it can be replaced with

                       

                           String group = ((TaskImpl) assignable).getTaskDefinition()
                                               .getCandidateGroupsExpression();
                      
                           assignable.setAssignee(defaultUsers.get(group));
                      
                      

                       

                      This uses cached data so scales linear. I know you are not using API classes/methods then, but this seems a valid usecase to me so the api should be extended I think. (there is the same 'problem' using swimlanes). If you file a jira issue to extend the assignable interface, I'll look into this issue further.

                       

                      Ronald

                      • 8. Re: NullPointerException on Assignment-Handler
                        Andre Muniz Newbie

                        Hi Ronald,

                         

                        Thanks very much for you help!

                         

                        I've just changed ExecutionImpl, and it's working now...