package com.artfess.activiti.def; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.activiti.engine.RepositoryService; import org.activiti.engine.impl.RepositoryServiceImpl; import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; import org.activiti.engine.impl.pvm.PvmActivity; import org.activiti.engine.impl.pvm.PvmTransition; import org.activiti.engine.impl.pvm.process.ActivityImpl; import org.activiti.engine.impl.pvm.process.TransitionImpl; import org.springframework.transaction.TransactionSystemException; import com.artfess.base.util.AppUtil; import com.artfess.base.util.BeanUtils; import com.artfess.base.util.Dom4jUtil; import com.artfess.base.util.FileUtil; import com.artfess.base.util.StringUtil; import com.artfess.bpm.api.cmd.ActionCmd; import com.artfess.bpm.api.constant.BpmConstants; import com.artfess.bpm.api.constant.NodeType; import com.artfess.bpm.api.context.ContextThreadUtil; import com.artfess.bpm.api.model.process.task.BpmTask; import com.artfess.bpm.persistence.manager.ActExecutionManager; import com.artfess.bpm.persistence.model.ActExecution; import com.artfess.bpm.util.ClassLoadUtil; public class BpmDefUtil { /** * 将通过设计器设计的流程定义xml添加监听器设置。 * * @param id * 流程定义ID * @param name * 流程定义名称 * @param xml * 流程定义xml。 * @return 转化过的xml。 * @throws Exception */ public static String transBpmDef(String id, String name, String xml) { try { ClassLoader loader = Thread.currentThread().getContextClassLoader(); InputStream is = loader .getResourceAsStream("com/artfess/bpmx/activiti/xml/transformDef.xsl"); if (is == null) { is = BpmDefUtil.class .getResourceAsStream("com/artfess/bpmx/activiti/xml/transformDef.xsl"); } Map map = new HashMap(); map.put("id", id); map.put("name", name); String result = Dom4jUtil.transXmlByXslt(xml, is, map); result = result.replace("<", "<").replace(">", ">") .replace("xmlns=\"\"", "").replace("&", "&"); return result; } catch (Exception ex) { throw new TransactionSystemException("转换流程定义出错", ex); } } /** * 将通过设计器设计的流程定义xml添加监听器设置。 * * @param id * 流程定义ID * @param name * 流程定义名称 * @param xml * 流程定义xml。 * @return 转化过的xml。 * @throws Exception */ public static String transFlashBpmDef(String id, String name, String xml) throws Exception { return ClassLoadUtil.transform(id, name, xml); } /** * 将节点之后的节点删除然后指向新的节点。 * * @param actDefId * 流程定义ID * @param nodeId * 流程节点ID * @param aryDestination * 需要跳转的节点 * @return Map 返回节点和需要恢复节点的集合。 */ @SuppressWarnings("unchecked") public static Map prepare(String actDefId, String nodeId, String[] aryDestination) { Map map = new HashMap(); RepositoryService repositoryService = AppUtil .getBean(RepositoryService.class); // 修改流程定义 ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService) .getDeployedProcessDefinition(actDefId); ActivityImpl curAct = processDefinition.findActivity(nodeId); List outTrans = curAct.getOutgoingTransitions(); ActivityImpl cloneCurAct = null; try { cloneCurAct = (ActivityImpl) FileUtil.cloneObject(curAct); List cloneOutTrans = (List) FileUtil .cloneObject(outTrans); map.put("outTrans", cloneOutTrans); } catch (Exception ex) { ex.printStackTrace(); } /** * 解决通过选择自由跳转指向同步节点导致的流程终止的问题。 在目标节点中删除指向自己的流转。 */ for (Iterator it = outTrans.iterator(); it.hasNext();) { PvmTransition transition = it.next(); PvmActivity activity = transition.getDestination(); List inTrans = activity.getIncomingTransitions(); for (Iterator itIn = inTrans.iterator(); itIn .hasNext();) { PvmTransition inTransition = itIn.next(); if (inTransition.getSource().getId().equals(curAct.getId())) { itIn.remove(); } } } curAct.getOutgoingTransitions().clear(); if (aryDestination != null && aryDestination.length > 0) { for (String dest : aryDestination) { // 创建一个连接 ActivityImpl destAct = processDefinition.findActivity(dest); // 条件同步 同步 需要先接相应的网关 再指向原来的目标节点 ActionCmd cmd = ContextThreadUtil.getActionCmd(); // 只需要处理 按流程图执行的方式 if (BeanUtils.isNotEmpty(cmd) && BeanUtils.isNotEmpty(cmd .getTransitVars(BpmConstants.BPM_TASK)) && "normal".equals(cmd .getTransitVars(BpmConstants.BACK_HAND_MODE))) { Map gateWayMap = new HashMap(); if (inInclusiveOrParallelGateway(cloneCurAct, NodeType.INCLUSIVEGATEWAY.getKey(), dest, gateWayMap)) { String afterGateWayActId = String.valueOf(gateWayMap .get("gateWayNodeId")); ActivityImpl gateWayAct = processDefinition .findActivity(afterGateWayActId); gateWayAct.getOutgoingTransitions().clear(); TransitionImpl transitionImpl = gateWayAct .createOutgoingTransition(); transitionImpl.setDestination(destAct); destAct = gateWayAct; updateRejectExecution(cmd,afterGateWayActId); } if (inInclusiveOrParallelGateway(cloneCurAct, NodeType.PARALLELGATEWAY.getKey(), dest, gateWayMap)) { String afterGateWayActId = String.valueOf(gateWayMap .get("gateWayNodeId")); ActivityImpl gateWayAct = processDefinition .findActivity(afterGateWayActId); gateWayAct.getOutgoingTransitions().clear(); TransitionImpl transitionImpl = gateWayAct .createOutgoingTransition(); transitionImpl.setDestination(destAct); destAct = gateWayAct; updateRejectExecution(cmd,afterGateWayActId); } } TransitionImpl transitionImpl = curAct .createOutgoingTransition(); transitionImpl.setDestination(destAct); } } map.put("activity", curAct); return map; } /** * 将临时节点清除掉,加回原来的节点。 * * @param map * void */ @SuppressWarnings("unchecked") public static void restore(Map map) { ActivityImpl curAct = (ActivityImpl) map.get("activity"); List outTrans = (List) map .get("outTrans"); curAct.getOutgoingTransitions().clear(); curAct.getOutgoingTransitions().addAll(outTrans); } /** * * @param curAct * 当前节点 * @param nodeType * NodeType.INCLUSIVEGATEWAY.getKey()(条件同步网关) * NodeType.PARALLELGATEWAY.getKey()(同步网关) * @param gateWayNodeId * 往后查询最近的结束网关节点id 用于当前节点的后续节点结束同步(条件)网关) * @return true 当前节点 curAct 前后都有网关,并且网关内不包含驳回的目标节点destNodeId 否则返回false */ public static boolean inInclusiveOrParallelGateway(ActivityImpl curAct, String nodeType, String destNodeId, Map gatewayMap) { gatewayMap.put("hasGateWay", false); Boolean preHasGateway = false; Boolean afterHasGateway = false; Set preNodeIds = new HashSet(); Set afterNodeIds = new HashSet(); hasGateWay(curAct.getIncomingTransitions(), "pre", nodeType, gatewayMap, preNodeIds); preHasGateway = (Boolean) gatewayMap.get("hasGateWay"); gatewayMap.put("hasGateWay", false); hasGateWay(curAct.getOutgoingTransitions(), "after", nodeType, gatewayMap, afterNodeIds); afterHasGateway = (Boolean) gatewayMap.get("hasGateWay"); // 往前往后查询节点都具有网关 ,则需要满足驳回的节点不能处于网关内 if (preHasGateway && afterHasGateway && !preNodeIds.contains(destNodeId) && !afterNodeIds.contains(destNodeId)) { return true; } else { return false; } } /** * * @param comingTransitions * 节点集合 * @param direction * pre | after 往前或者往后查询 * @param nodeType * NodeType.INCLUSIVEGATEWAY.getKey()(条件同步网关) * NodeType.PARALLELGATEWAY.getKey()(同步网关) * @param Map * gatewayMap * */ public static void hasGateWay(List comingTransitions, String direction, String nodeType, Map gatewayMap, Set nodeIds) { for (PvmTransition pvmTransition : comingTransitions) { if (!(Boolean) gatewayMap.get("hasGateWay")) { PvmActivity pvmActivity = null; if ("pre".equals(direction)) { pvmActivity = pvmTransition.getSource(); } if ("after".equals(direction)) { pvmActivity = pvmTransition.getDestination(); } if(nodeIds.contains(pvmActivity.getId())){ continue; } nodeIds.add(pvmActivity.getId()); if (nodeType.equals(pvmActivity.getProperty("type"))) { // 找到相应的节点类型 hasGateWay gatewayMap.put("hasGateWay", true); gatewayMap.put("gateWayNodeId", pvmActivity.getId()); } else { List _comingTransitions = new ArrayList(); if ("pre".equals(direction)) { _comingTransitions = pvmActivity .getIncomingTransitions(); } if ("after".equals(direction)) { _comingTransitions = pvmActivity .getOutgoingTransitions(); } hasGateWay(_comingTransitions, direction, nodeType, gatewayMap, nodeIds); } } } } private static void updateRejectExecution(ActionCmd cmd,String afterGateWayActID){ // 更新act_ru_execution 表的数据 BpmTask bpmTask = (BpmTask) cmd .getTransitVars(BpmConstants.BPM_TASK); String execId = bpmTask.getExecId(); ActExecutionManager actExecutionManager = AppUtil .getBean(ActExecutionManager.class); ActExecution actExecution = actExecutionManager.get(execId); //处理同步网关内包含会签节点(并行)时,同步网关内人员驳回情况 while(StringUtil.isNotEmpty(actExecution.getParentId()) && !actExecution.getParentId().equals(actExecution.getProcInstId())) { actExecution = actExecutionManager.get(actExecution.getParentId()); actExecutionManager.updateRejectExecution(actExecution.getParentId(), execId,actExecution.getActId()); } actExecutionManager.updateRejectExecution(actExecution.getParentId(), execId,afterGateWayActID); } }