javataskbusiness-process-managementcamunda

Manually change task on running process-instance


in order of developing a custom BPM Application there is one feature we used with another BPM engine provider and like to use it with camunda too. The targeted functionality is about setting/reset running process instances to a specified task other than the current active one. From our perspective necessary when e.g.:

Finally I didn't really found a simple function to do this but worked out some custom code which worked with some limitations. There are some weaknesses and uncertainities within this code so that I have the following question:

Did I miss an alternative way to achieve this or is the following approach correct or is it even fully unsupported at the moment ?

The current weaknesses imho:

Here's the code (experimental snippet of our camunda service facade) :

@Inject
protected HistoryService histService;
@Inject
protected TaskService taskService;
@Inject
protected ManagementService managementService;
@Inject
protected RuntimeService runtimeService;
@Inject
protected IdentityService identityService;
@Inject
protected RepositoryService repositoryService;
@Inject
protected FormService formService;
@Inject
protected ProcessEngine processEngine;


public void startTask(String processInstanceId, String taskKey) {
    Collection<TaskDefinition> taskDefs = getAvailableTasks(
            processInstanceId);
    TaskEntity newTask = null;
    TaskDefinition taskDef = null;
    for (TaskDefinition taskDefinition : taskDefs) {
        if (taskDefinition.getKey().equals(taskKey)) {
            taskDef = taskDefinition;
            break;
        }
    }
    boolean taskDefExists = taskDef != null;
    List<Task> runningTasksByKey = getTasksByKey(taskKey, processInstanceId);
    boolean taskIsAlreadyRunning = runningTasksByKey != null
            && runningTasksByKey.size() > 0;
    if (taskDefExists && !taskIsAlreadyRunning) {
        newTask = (TaskEntity) taskService.newTask();
        ProcessInstance procInst = getProcessInstance(processInstanceId);
        ExecutionEntity procInstEntity = (ExecutionEntity) procInst;
        String taskName = (String) taskDef.getNameExpression().
                getExpressionText();
//            String taskAssigne = (String) taskDef.getAssigneeExpression().
//                    getValue(
//                            procInstEntity);
//            newTask.setAssignee(taskAssigne);
            newTask.setTaskDefinitionKey(taskDef.getKey());
            newTask.setProcessInstance(procInstEntity);
            newTask.setTaskDefinition(taskDef);
            newTask.setName(taskName);
            newTask.setProcessInstanceId(processInstanceId);
            newTask.setProcessDefinitionId(procInstEntity.
                    getProcessDefinitionId());
            taskService.saveTask(newTask);

        TaskServiceImpl taskServiceImpl = (TaskServiceImpl) BpmPlatform.
                getProcessEngineService().getDefaultProcessEngine().
                getTaskService();
        CommandExecutor commandExecutor = taskServiceImpl.
                getCommandExecutor();
        ExecutionEntity executionEntity = commandExecutor.execute(
                new SaveTaskActivityInstanceCmd(newTask,
                        procInstEntity));
//            commandExecutor.execute(new `SaveTaskHistoricActivityInstanceCmd(executionEntity, newTask));`
    }
}

public Collection<TaskDefinition> getAvailableTasks(String processInstanceId) {
            Map<String, TaskDefinition> taskDefs = null;
            Collection<TaskDefinition> taskDefObjects = null;
            if (processInstanceId != null) {
                ProcessInstanceQuery procInstQuery = runtimeService.
                        createProcessInstanceQuery().processInstanceId(
                                processInstanceId);
                ProcessDefinitionEntity procDefEntity = getProcessDefinitionEager(
                        processInstanceId);
                taskDefs = procDefEntity.getTaskDefinitions();
            }
            taskDefObjects = (Collection<TaskDefinition>) (taskDefs != null ? taskDefs.
                    values() : new ArrayList<TaskDefinition>());
            return taskDefObjects;
}

public ProcessDefinitionEntity getProcessDefinitionEager(
        String processInstanceId) {
    ProcessInstanceQuery procInstQuery = runtimeService.
            createProcessInstanceQuery().processInstanceId(
                    processInstanceId);
    ProcessInstance procInst = procInstQuery.singleResult();
    String procDefId = procInst.getProcessDefinitionId();
    return (ProcessDefinitionEntity) repositoryService.getProcessDefinition(
            procDefId);
}

public List<Task> getTasksByKey(String taskKey, String processInstanceId) {
    List<Task> tasks = taskService.createTaskQuery().processInstanceId(
            processInstanceId).taskDefinitionKey(taskKey).list();
    return tasks;
}


public class SaveTaskActivityInstanceCmd implements Command<ExecutionEntity>,  
      Serializable {

    private TaskEntity newTask;
    private ExecutionEntity procInstEntity;

    public SaveTaskActivityInstanceCmd(TaskEntity newTaskInit,
            ExecutionEntity procInstEntityInit) {
        this.newTask = newTaskInit;
        this.procInstEntity = procInstEntityInit;
    }


    public ExecutionEntity execute(CommandContext commandContext) {
          ActivityImpl actImpl = new ActivityImpl(newTask.
                getTaskDefinitionKey(),
                procInstEntity.getProcessDefinition());
          actImpl.setActivityBehavior(new UserTaskActivityBehavior(
                new CdiExpressionManager(), newTask.getTaskDefinition()));
          ExecutionEntity execEntity = new ExecutionEntity();
          execEntity.setActivity(actImpl);
          execEntity.setActivityInstanceId(newTask.getTaskDefinitionKey()
                + ":" + newTask.getId());
          execEntity.setEventName(newTask.getEventName());
          execEntity.setProcessDefinitionId(newTask.getProcessDefinitionId());
          execEntity.setActive(true);
          execEntity.setProcessInstance(procInstEntity);
          commandContext.getExecutionManager().insert(execEntity);
          return execEntity;
     }
}

I appreciate any hint or advice :-)


Solution

  • I wouldn't mess with the process instance on that level, as you already noticed, you are bypassing camundas services. When faced with a similar problem, we went with the following:

    1. cancel the process instance of the old process version
    2. start a new instance of the extended process and forward it programmatically to the desired state ...

    Another option: model an entry point (message start event) inside the new process version. Then, instead of programmatically forwarding the instance to the desired state, just start the new instance via the event and pass all process variables of the old instance ...