As we transition to the new Hyland Community, some post links may be temporarily disrupted as we finalize redirects. We apologize for the inconvenience and are working to resolve this as quickly as possible. Details.
import org.activiti.engine.ProcessEngine; import org.activiti.engine.ProcessEngines; import org.activiti.engine.RuntimeService; import org.activiti.engine.delegate.event.ActivitiEvent; import org.activiti.engine.delegate.event.ActivitiEventListener; import org.activiti.engine.delegate.event.ActivitiEventType; import org.activiti.engine.impl.bpmn.behavior.TaskActivityBehavior; import org.activiti.engine.impl.pvm.delegate.ActivityExecution; import org.activiti.engine.runtime.Execution; import org.activiti.engine.runtime.ExecutionQuery; public class ThreadDelegate extends TaskActivityBehavior { @Override public void execute(ActivityExecution execution) throws Exception { System.out.println("Started thread delegate for execution id " + execution.getId()); Object counterObj = execution.getVariable("counter"); if(counterObj == null) { execution.setVariable("counter", 0); System.out.println("Counter initialised at 0"); } else { int counter = (int) counterObj; counter++; execution.setVariable("counter", counter); System.out.println("Counter incremented to " + counter); } final String executionId = execution.getId(); final Thread t = new Thread() { @Override public void run() { System.out.println("Thread running"); // Forcing the thread to sleep causes the process the execute normally // try { // Thread.sleep(5000); // } catch (InterruptedException e) { } signalWaitState(); /* KLUDGE alert! * This does work but I hope to achieve signalling without a polling loop. */ /* int retries = 0; while(retries < 5) { try { signalWaitState(); return; } catch (NullPointerException e) { retries++; System.out.println("Waiting before retry " + retries); try { Thread.sleep(1000); } catch (InterruptedException e2) { } } } */ } /* * Sometimes a NPE exception is thrown * at org.activiti.engine.impl.persistence.entity.ExecutionEntity.signal(ExecutionEntity.java:375) * unless the thread is forced to sleep first. Presumably this is because the wait state has not been * executed yet. */ private void signalWaitState() { ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); RuntimeService runtimeService = processEngine.getRuntimeService(); runtimeService.signal(executionId); System.out.println("Signalled exeuection id " + executionId); } }; /* * The purpose of this event listener was to ensure that the waitState has been * entered before starting the delegate thread. This was intended to prevent the * intermittent NPE when called signal() when delegate thread completes execution. * * Even though the executionId is valid the query returns a null execution. */ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); RuntimeService runtimeService = processEngine.getRuntimeService(); runtimeService.addEventListener(new ActivitiEventListener() { @Override public void onEvent(ActivitiEvent event) { RuntimeService runtimeService = event.getEngineServices().getRuntimeService(); System.out.println("Event type: " + event.getType() + " executionId: " + event.getExecutionId() + " piid: " + event.getProcessInstanceId()); // TODO: filter on executionId try { ExecutionQuery q = runtimeService.createExecutionQuery(); q.executionId(event.getExecutionId()); Execution execution = q.singleResult(); String activityId = execution.getActivityId(); System.out.println("Activity ID: " + activityId); if("waitState".equals(activityId)) { t.start(); } System.out.println("Started delegate thread."); } finally { runtimeService.removeEventListener(this); } } @Override public boolean isFailOnException() { return true; } }); this.leave(execution); System.out.println("Left service task"); // Start the thread here unless using the event listener above // t.start(); System.out.println("Started delegate thread."); } }