标签:style blog http io ar color os sp java
最近在搞openwebflow的工作流节点自由跳转功能,在网上看了一些资料,感觉不是很好,总结原因如下:
那么就自己动手吧!操作流程其实也简单,大概如下:
注意:直接删除当前节点会报错,因为它还在流程之中,所以要先解除任务与当前执行execution的关联;
以上操作如何安全的实现呢?看了一下源码,经过多次痛苦的尝试,积累了不少教训:
那么怎么办呢?我想说的是,Activiti的封装做得很厚,想完全看懂是太难的。目前我还没想完全看懂,直接吐槽一下,与后人分享其中的痛苦:
public static void setCommandContext(CommandContext commandContext) { getStack(commandContextThreadLocal).push(commandContext); }
总之,代码看得那是相当郁闷!debug的时候,调用栈极其深,而且大部分都会落在如下两段代码中:
代码1:
public <T> T execute(CommandConfig config, Command<T> command) { if (!log.isDebugEnabled()) { // do nothing here if we cannot log return next.execute(config, command); } log.debug("\n"); log.debug("--- starting {} --------------------------------------------------------", command.getClass().getSimpleName()); try { return next.execute(config, command); } finally { log.debug("--- {} finished --------------------------------------------------------", command.getClass().getSimpleName()); log.debug("\n"); } }
代码2:
try { // Push on stack Context.setCommandContext(context); Context.setProcessEngineConfiguration(processEngineConfiguration); return next.execute(config, command); } catch (Exception e) { context.exception(e); } finally { try { if (!contextReused) { context.close(); } } finally { // Pop from stack Context.removeCommandContext(); Context.removeProcessEngineConfiguration(); } }
由于时间关系,我没有细细的去理解每个类,但最终还是找出了一个极妙、极安全的方法,那就是:自己写Command!然后扔给CommandExecutor()了事!
最终形成的代码如下所示:
package org.openwebflow.ctrl; import org.activiti.engine.ProcessEngine; import org.activiti.engine.TaskService; import org.activiti.engine.impl.RuntimeServiceImpl; import org.activiti.engine.impl.interceptor.Command; import org.activiti.engine.impl.interceptor.CommandContext; import org.activiti.engine.impl.persistence.entity.ExecutionEntity; import org.activiti.engine.impl.persistence.entity.TaskEntity; import org.activiti.engine.impl.pvm.process.ActivityImpl; import org.openwebflow.util.ActivityUtils; public class TaskFlowControlService { ProcessEngine _processEngine; private String _processId; public TaskFlowControlService(ProcessEngine processEngine, String processId) { _processEngine = processEngine; _processId = processId; } /** * 跳转至指定活动节点 * * @param targetTaskDefinitionKey * @throws Exception */ public void jump(String targetTaskDefinitionKey) throws Exception { TaskEntity currentTask = (TaskEntity) _processEngine.getTaskService().createTaskQuery() .processInstanceId(_processId).singleResult(); jump(currentTask, targetTaskDefinitionKey); } /** * * @param currentTaskEntity * 当前任务节点 * @param targetTaskDefinitionKey * 目标任务节点(在模型定义里面的节点名称) * @throws Exception */ private void jump(final TaskEntity currentTaskEntity, String targetTaskDefinitionKey) throws Exception { final ActivityImpl activity = ActivityUtils.getActivity(_processEngine, currentTaskEntity.getProcessDefinitionId(), targetTaskDefinitionKey); final ExecutionEntity execution = (ExecutionEntity) _processEngine.getRuntimeService().createExecutionQuery() .executionId(currentTaskEntity.getExecutionId()).singleResult(); final TaskService taskService = _processEngine.getTaskService(); //包装一个Command对象 ((RuntimeServiceImpl) _processEngine.getRuntimeService()).getCommandExecutor().execute( new Command<java.lang.Void>() { @Override public Void execute(CommandContext commandContext) { //创建新任务 execution.setActivity(activity); execution.executeActivity(activity); //删除当前的任务 //不能删除当前正在执行的任务,所以要先清除掉关联 currentTaskEntity.setExecutionId(null); taskService.saveTask(currentTaskEntity); taskService.deleteTask(currentTaskEntity.getId(), true); return null; } }); } }
最后写了一个测试类,代码如下:
@Test public void testTaskSequence() throws Exception { //_processDef对应于vacationRequest流程,参见https://github.com/bluejoe2008/openwebflow/blob/master/models/test.bpmn ProcessInstance instance = _processEngine.getRuntimeService().startProcessInstanceByKey(_processDef.getKey()); String instanceId = instance.getId(); TaskService taskService = _processEngine.getTaskService(); Task task1 = taskService.createTaskQuery().singleResult(); Assert.assertEquals("step2", task1.getTaskDefinitionKey()); Map<String, Object> vars = new HashMap<String, Object>(); vars.put("vacationApproved", false); vars.put("numberOfDays", 10); vars.put("managerMotivation", "get sick"); String taskId = taskService.createTaskQuery().taskCandidateUser("kermit").singleResult().getId(); taskService.complete(taskId, vars); Task task2 = taskService.createTaskQuery().singleResult(); Assert.assertEquals("adjustVacationRequestTask", task2.getTaskDefinitionKey()); TaskFlowControlService tfcs = new TaskFlowControlService(_processEngine, instanceId); //跳回至 step2 tfcs.jump("step2"); Task task3 = taskService.createTaskQuery().singleResult(); Assert.assertEquals("step2", task3.getTaskDefinitionKey()); //确认权限都拷贝过来了 //management可以访问该task Assert.assertEquals(1, taskService.createTaskQuery().taskCandidateGroup("management").count()); //engineering不可以访问该task Assert.assertEquals(0, taskService.createTaskQuery().taskCandidateGroup("engineering").count()); //确认历史轨迹里已保存 List<HistoricActivityInstance> activities = _processEngine.getHistoryService() .createHistoricActivityInstanceQuery().processInstanceId(instanceId).list(); Assert.assertEquals(5, activities.size()); Assert.assertEquals("step1", activities.get(0).getActivityId()); Assert.assertEquals("step2", activities.get(1).getActivityId()); Assert.assertEquals("requestApprovedDecision", activities.get(2).getActivityId()); Assert.assertEquals("adjustVacationRequestTask", activities.get(3).getActivityId()); Assert.assertEquals("step2", activities.get(4).getActivityId()); //测试一下往前跳 tfcs.jump("adjustVacationRequestTask"); Task task4 = taskService.createTaskQuery().singleResult(); Assert.assertEquals("adjustVacationRequestTask", task4.getTaskDefinitionKey()); activities = _processEngine.getHistoryService().createHistoricActivityInstanceQuery() .processInstanceId(instanceId).list(); Assert.assertEquals(6, activities.size()); Assert.assertEquals("adjustVacationRequestTask", activities.get(5).getActivityId()); _processEngine.getRuntimeService().deleteProcessInstance(instanceId, "test"); }
标签:style blog http io ar color os sp java
原文地址:http://blog.csdn.net/bluejoe2000/article/details/41778737