Activiti6 is what I use to temporarily add a UserTask to the process. I want to do the following scenario:
When user A approves, user B is required to approve temporarily, and user B is not in the pre-defined process, so A UserTask needs to be added temporarily dynamically.
But I found two problems:
org.activiti.engine.ActivitiException: Programmatic error: no current flow element found or invalid type: null. Halting.
at org.activiti.engine.impl.agenda.TriggerExecutionOperation.run(TriggerExecutionOperation.java:49)
at org.activiti.engine.impl.interceptor.CommandInvoker.executeOperation(CommandInvoker.java:73)
at org.activiti.engine.impl.interceptor.CommandInvoker.executeOperations(CommandInvoker.java:57)
at org.activiti.engine.impl.interceptor.CommandInvoker.execute(CommandInvoker.java:42)
at org.activiti.engine.impl.interceptor.TransactionContextInterceptor.execute(TransactionContextInterceptor.java:48)
at org.activiti.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:63)
at org.activiti.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:29)
at org.activiti.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:44)
at org.activiti.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:39)
at org.activiti.engine.impl.TaskServiceImpl.complete(TaskServiceImpl.java:182)
at org.destiny.activiti.coreapi.TaskServiceTest.test(TaskServiceTest.java:357)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.activiti.engine.test.ActivitiRule$1.evaluate(ActivitiRule.java:116)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
ACT_HI_TASKINST table, the task added temporarily does not have processInstanceId or other process information
And there is my code:
main test
@Test
public void test() {
ProcessInstance processInstance = activitiRule.getRuntimeService().startProcessInstanceByKey("my-process");
TaskService taskService = activitiRule.getTaskService();
Task task = taskService.createTaskQuery().singleResult();
log.info("task: {}", ToStringBuilder.reflectionToString(task, ToStringStyle.JSON_STYLE));
activitiRule.getManagementService().executeCommand(new ShareniuCountersignAddCmd(task.getExecutionId(), "camery"));
Task destiny = taskService.createTaskQuery().taskAssignee("destiny").singleResult();
taskService.complete(destiny.getId());
historicTaskInstances = activitiRule.getHistoryService().createHistoricTaskInstanceQuery().list();
Task camery = taskService.createTaskQuery().taskAssignee("camery").singleResult();
taskService.complete(camery.getId()); // <=== will throw an Exception
}
CountersignAddCmd
public class CountersignAddCmd implements Command<Void> {
protected String executionId;
protected String assignee;
public CountersignAddCmd(String executionId, String assignee) {
this.executionId = executionId;
this.assignee = assignee;
}
@Override
public Void execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration = commandContext.getProcessEngineConfiguration();
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
TaskService taskService = processEngineConfiguration.getTaskService();
IdGenerator idGenerator = processEngineConfiguration.getIdGenerator();
// get Execution
Execution execution = runtimeService.createExecutionQuery().executionId(executionId).singleResult();
ExecutionEntity executionEntity = (ExecutionEntity) execution;
// get parent ExecutionEntity
ExecutionEntity parent = executionEntity.getParent();
// create ExecutionEntity
ExecutionEntity newExecution = commandContext.getExecutionEntityManager().createChildExecution(parent);
newExecution.setActive(true);
newExecution.setConcurrent(true);
newExecution.setScope(false);
Task newTask = taskService.createTaskQuery().executionId(executionId).singleResult();
TaskEntity t = (TaskEntity) newTask;
TaskEntity taskEntity = new TaskEntityImpl();
taskEntity.setCreateTime(new Date());
taskEntity.setProcessDefinitionId(t.getProcessDefinitionId());
taskEntity.setTaskDefinitionKey(t.getTaskDefinitionKey());
taskEntity.setProcessInstanceId(t.getProcessInstanceId());
taskEntity.setExecutionId(newExecution.getId());
taskEntity.setName(newTask.getName());
String taskId = idGenerator.getNextId();
taskEntity.setId(taskId);
taskEntity.setRevision(0);
taskEntity.setExecution(newExecution);
taskEntity.setAssignee(assignee);
taskService.saveTask(taskEntity);
return null;
}
}
@DestinyWang it will be great if you provide a project to reproduce the problem. A maven project hosted in GitHub with a test failing will be great. so we can debug what is going on and try to help.
With the information provided here it is quite difficult to see what might be failing.
@balsarori can you spot the problem?
@salaboy ok here is the project:
Hopefully you can figure out the cause of the problem, and if you can implement how can I do what I'm talking about
@DestinyWang adding a task on the fly to a process like that will not work. The engine doesn't know what to execute next when that task completes.
@balsarori What puzzles me is how do I tell the engine what to do next
Most helpful comment
@DestinyWang it will be great if you provide a project to reproduce the problem. A maven project hosted in GitHub with a test failing will be great. so we can debug what is going on and try to help.
With the information provided here it is quite difficult to see what might be failing.
@balsarori can you spot the problem?