1 Reply Latest reply on Jun 21, 2011 2:29 AM by saig0

    [jBPM4.4] custom activity has an end time before this activity is leaveds the activity

    saig0

      Hi,

       

      I note that a custom activity has an end time before this activity is leaved.

       

      process:

       

      <?xml version="1.0" encoding="UTF-8"?>
      
      
      <process name="HistoryServiceTest" xmlns="http://jbpm.org/4.4/jpdl">
                <start name="start" g="77,144,48,48">
                          <transition to="custom-state" />
                </start>
                <custom name="custom-state" g="175,140,105,52" class="processes.classes.SimpleCustomState">
                          <transition to="end" />
                </custom>
                <end name="end" g="324,144,48,48" />
      </process>
      
      

       

      SimpleCustomState.java:

       

      package processes.classes; 
      
      import java.util.Map; 
      import org.jbpm.api.activity.ActivityExecution;
      import org.jbpm.api.activity.ExternalActivityBehaviour; 
      
      public class SimpleCustomState implements ExternalActivityBehaviour
      {
          private static final long serialVersionUID = 1L;
      
          public void execute(ActivityExecution execution) throws Exception    {
              execution.waitForSignal();
          }
      
          public void signal(ActivityExecution execution, String signalName, Map<String, ?> parameters)
                  throws Exception    {
              execution.takeDefaultTransition();
          }
      
      }
      
      

       

      test:

       

      package services; 
      
      import org.junit.Assert.*;
      import java.util.Date;
      import java.util.List;
      import java.util.zip.ZipInputStream;  
      import org.jbpm.api.*;
      import org.junit.*; 
      
      public class HistoryServiceTest
      { 
          private HistoryService    historyService;
          private ExecutionService  executionService;
          private RepositoryService repositoryService;
      
          @Before
          public void setup()    {
              initEngine();
              deployProcess();
          }
      
          public void initEngine()    {
              ProcessEngine processEngine = new Configuration().setResource("default.jbpm.cfg.xml")
                      .buildProcessEngine();
              executionService = processEngine.getExecutionService();
              historyService = processEngine.getHistoryService();
              repositoryService = processEngine.getRepositoryService();
          }
      
          public void deployProcess()    {
              ZipInputStream zipInputStream = new ZipInputStream(getClass().getResourceAsStream("/jbpm.zip"));
              repositoryService.createDeployment().addResourcesFromZipInputStream(zipInputStream).setName("test")
                      .setTimestamp(new Date().getTime()).deploy();
          }
      
          public String startProcess()    {
              ProcessInstance processInstance = executionService.startProcessInstanceByKey("HistoryServiceTest");
              return processInstance.getId();
          }
      
          private boolean isRunning(String processInstanceId)    {
              ProcessInstance pi = executionService.findProcessInstanceById(processInstanceId);
              return pi != null ? pi.isEnded() : false;
          }
      
          @Test
          public void testHasEndDateForEndedCustomActivity()    {
              String processInstanceId = startProcess();
              String activityName = "custom-state";
              assertTrue(executionService.findProcessInstanceById(processInstanceId).isActive(activityName));
      
      
              executionService.signalExecutionById(processInstanceId, "");
              assertFalse(isRunning(processInstanceId));
      
      
              HistoryActivityInstance historyActivityInstance = historyService.createHistoryActivityInstanceQuery()
                      .processInstanceId(processInstanceId).activityName(activityName).uniqueResult();
              assertNotNull(historyActivityInstance.getEndTime());
          }
      
          @Test
          public void testHasNoEndDateForActiveCustomActivity()    {
              String processInstanceId = startProcess();
              String activityName = "custom-state";
              assertTrue(executionService.findProcessInstanceById(processInstanceId).isActive(activityName));
      
      
              List<HistoryActivityInstance> historyActivityInstances = historyService
                      .createHistoryActivityInstanceQuery().processInstanceId(processInstanceId)
                      .activityName(activityName).list();
              if (!historyActivityInstances.isEmpty())
              {
                  for (HistoryActivityInstance historyActivityInstance : historyActivityInstances)
                      assertNull(historyActivityInstance.getEndTime()); // this fail!
              }
          }
      }
      

       

      After I looking for a reason, I found something in class UserCodeActivityBehaviour:

       

      public void execute(ActivityExecution execution) throws Exception {
          ActivityBehaviour activityBehaviour = (ActivityBehaviour) customActivityReference.getObject(execution);
          activityBehaviour.execute(execution);
          ((ExecutionImpl)execution).historyAutomatic();
        }
      

       

      This methode create a object of class HistoryActivityInstanceImpl and call:

       

      public HistoryAutomaticInstanceImpl(HistoryProcessInstance historyProcessInstanceImpl, ExecutionImpl execution) {
          super(historyProcessInstanceImpl, execution);
          setEndTime(Clock.getTime());
        }
      

       

      Now I want to ask why this was not implemented like in class StateActivity?

      And how to fix this bug?

        • 1. Re: [jBPM4.4] custom activity has an end time before this activity is leaveds the activity
          saig0

          A solution is to change the class UserCodeActivityBehavior:

           

           

             public void execute(ActivityExecution execution) throws Exception
              {
                  ActivityBehaviour activityBehaviour = (ActivityBehaviour) customActivityReference
                          .getObject(execution);
                  activityBehaviour.execute(execution);
          
          
                  Propagation propagation = ((ExecutionImpl) execution).getPropagation();
                  if (propagation.equals(Propagation.WAIT))
                      ((ExecutionImpl) execution).historyActivityStart();
                  else
                      ((ExecutionImpl) execution).historyAutomatic();
              }
          
          
              public void signal(ActivityExecution execution, String signalName, Map<String, ?> parameters)
                      throws Exception
              {
                  ExternalActivityBehaviour externalActivityBehaviour = (ExternalActivityBehaviour) customActivityReference
                          .getObject(execution);
                  externalActivityBehaviour.signal(execution, signalName, parameters);
          
          
                  TransitionImpl transition = ((ExecutionImpl) execution).getTransition();
                  if (transition != null)
                      ((ExecutionImpl) execution).historyActivityEnd(transition.getName());
                  else
                      ((ExecutionImpl) execution).historyActivityEnd();
              }