activiti-跟踪流程图颜色变化之一篇

我喜欢简要文字 主要还是发代码为主了,希望发现问题可以一起探讨!

我用的框架是spring mvc

controller

/**
* <功能简述>流程跟踪图
* <功能详细描述>
* @param processInstanceId 流程实例id
* @param response
* @throws Exception
* @see [类、类#方法、类#成员]
*/
@RequestMapping("graphHistoryProcessInstance")
public void graphHistoryProcessInstance(
@RequestParam("processInstanceId") String processInstanceId,
HttpServletResponse response) throws Exception {
Command cmd = new HistoryProcessInstanceDiagramCmd(
processInstanceId);

InputStream is = workspaceService.executeCommand(
cmd);
response.setContentType("image/png");

int len = 0;
byte[] b = new byte[1024];

while ((len = is.read(b, 0, 1024)) != -1) {
response.getOutputStream().write(b, 0, len);
}
is.close();
}

HistoryProcessInstanceDiagramCmd.java

package com.plate.bpm.graph;

import java.io.*;

import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;

public class HistoryProcessInstanceDiagramCmd implements Command {
protected String historyProcessInstanceId;

public HistoryProcessInstanceDiagramCmd(String historyProcessInstanceId) {
this.historyProcessInstanceId = historyProcessInstanceId;
}

public InputStream execute(CommandContext commandContext) {
try {
CustomProcessDiagramGenerator customProcessDiagramGenerator = new CustomProcessDiagramGenerator();

return customProcessDiagramGenerator
.generateDiagram(historyProcessInstanceId);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}


CustomProcessDiagramGenerator.java

package com.plate.bpm.graph;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Ellipse2D.Double;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;


import org.activiti.bpmn.constants.BpmnXMLConstants;
import org.activiti.bpmn.model.Artifact;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.FlowElementsContainer;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.GraphicInfo;
import org.activiti.bpmn.model.Lane;
import org.activiti.bpmn.model.Pool;
import org.activiti.bpmn.model.SequenceFlow;

import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.HistoricActivityInstanceQueryImpl;
import org.activiti.engine.impl.Page;
import org.activiti.engine.impl.cmd.GetBpmnModelCmd;
import org.activiti.engine.impl.cmd.GetDeploymentProcessDefinitionCmd;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;

import org.apache.commons.io.FilenameUtils;

/**
* 流程图绘制工具
*/
public class CustomProcessDiagramGenerator {
public static final int OFFSET_SUBPROCESS = 5;
public static final int OFFSET_TASK = 20;
private static List taskType = new ArrayList();
private static List eventType = new ArrayList();
private static List gatewayType = new ArrayList();
private static List subProcessType = new ArrayList();
private static Color RUNNING_COLOR = Color.RED;
private static Color HISTORY_COLOR = Color.GREEN;
private static Color SKIP_COLOR = Color.GRAY;
private static Stroke THICK_BORDER_STROKE = new BasicStroke(3.0f);
private int minX;
private int minY;

public CustomProcessDiagramGenerator() {
init();
}

protected static void init() {
taskType.add(BpmnXMLConstants.ELEMENT_TASK_MANUAL);
taskType.add(BpmnXMLConstants.ELEMENT_TASK_RECEIVE);
taskType.add(BpmnXMLConstants.ELEMENT_TASK_SCRIPT);
taskType.add(BpmnXMLConstants.ELEMENT_TASK_SEND);
taskType.add(BpmnXMLConstants.ELEMENT_TASK_SERVICE);
taskType.add(BpmnXMLConstants.ELEMENT_TASK_USER);

gatewayType.add(BpmnXMLConstants.ELEMENT_GATEWAY_EXCLUSIVE);
gatewayType.add(BpmnXMLConstants.ELEMENT_GATEWAY_INCLUSIVE);
gatewayType.add(BpmnXMLConstants.ELEMENT_GATEWAY_EVENT);
gatewayType.add(BpmnXMLConstants.ELEMENT_GATEWAY_PARALLEL);

eventType.add("intermediateTimer");
eventType.add("intermediateMessageCatch");
eventType.add("intermediateSignalCatch");
eventType.add("intermediateSignalThrow");
eventType.add("messageStartEvent");
eventType.add("startTimerEvent");
eventType.add(BpmnXMLConstants.ELEMENT_ERROR);
eventType.add(BpmnXMLConstants.ELEMENT_EVENT_START);
eventType.add("errorEndEvent");
eventType.add(BpmnXMLConstants.ELEMENT_EVENT_END);

subProcessType.add(BpmnXMLConstants.ELEMENT_SUBPROCESS);
subProcessType.add(BpmnXMLConstants.ELEMENT_CALL_ACTIVITY);
}

public InputStream generateDiagram(String processInstanceId)
throws IOException {
HistoricProcessInstance historicProcessInstance = Context
.getCommandContext().getHistoricProcessInstanceEntityManager()
.findHistoricProcessInstance(processInstanceId);
String processDefinitionId = historicProcessInstance
.getProcessDefinitionId();
GetBpmnModelCmd getBpmnModelCmd = new GetBpmnModelCmd(
processDefinitionId);
BpmnModel bpmnModel = getBpmnModelCmd.execute(Context
.getCommandContext());
Point point = getMinXAndMinY(bpmnModel);
this.minX = point.x;
this.minY = point.y;
this.minX = (this.minX <= 5) ? 5 : this.minX;
this.minY = (this.minY <= 5) ? 5 : this.minY;
this.minX -= 5;
this.minY -= 5;

ProcessDefinitionEntity definition = new GetDeploymentProcessDefinitionCmd(
processDefinitionId).execute(Context.getCommandContext());
String diagramResourceName = definition.getDiagramResourceName();
String deploymentId = definition.getDeploymentId();
byte[] bytes = Context
.getCommandContext()
.getResourceEntityManager()
.findResourceByDeploymentIdAndResourceName(deploymentId,
diagramResourceName).getBytes();
InputStream originDiagram = new ByteArrayInputStream(bytes);
BufferedImage image = ImageIO.read(originDiagram);

HistoricActivityInstanceQueryImpl historicActivityInstanceQueryImpl = new HistoricActivityInstanceQueryImpl();
historicActivityInstanceQueryImpl.processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceStartTime().asc();

Page page = new Page(0, 100);
List activityInstances = Context
.getCommandContext()
.getHistoricActivityInstanceEntityManager()
.findHistoricActivityInstancesByQueryCriteria(
historicActivityInstanceQueryImpl, page);

this.drawHistoryFlow(image, processInstanceId);

for (HistoricActivityInstance historicActivityInstance : activityInstances) {
String historicActivityId = historicActivityInstance
.getActivityId();
ActivityImpl activity = definition.findActivity(historicActivityId);

if (activity != null) {
if (historicActivityInstance.getEndTime() == null) {
// 节点正在运行中
signRunningNode(image, activity.getX(),
activity.getY(), activity.getWidth(),
activity.getHeight(),
historicActivityInstance.getActivityType());
} else {
String deleteReason = null;

if (historicActivityInstance.getTaskId() != null) {
deleteReason = Context
.getCommandContext()
.getHistoricTaskInstanceEntityManager()
.findHistoricTaskInstanceById(
historicActivityInstance.getTaskId())
.getDeleteReason();
}

// 节点已经结束
if ("跳过".equals(deleteReason)) {
signSkipNode(image, activity.getX(),
activity.getY(),
activity.getWidth(), activity.getHeight(),
historicActivityInstance.getActivityType());
} else {
signHistoryNode(image, activity.getX(),
activity.getY() ,
activity.getWidth(), activity.getHeight(),
historicActivityInstance.getActivityType());
}
}
}
}

ByteArrayOutputStream out = new ByteArrayOutputStream();
String formatName = getDiagramExtension(diagramResourceName);
ImageIO.write(image, formatName, out);

return new ByteArrayInputStream(out.toByteArray());
}

private static String getDiagramExtension(String diagramResourceName) {
return FilenameUtils.getExtension(diagramResourceName);
}

/**
* 标记运行节点
*
* @param image
* 原始图片
* @param x
* 左上角节点坐在X位置
* @param y
* 左上角节点坐在Y位置
* @param width
* 宽
* @param height
* 高
* @param activityType
* 节点类型
*/
private static void signRunningNode(BufferedImage image, int x, int y,
int width, int height, String activityType) {
Color nodeColor = RUNNING_COLOR;
Graphics2D graphics = image.createGraphics();

try {
drawNodeBorder(x, y, width, height, graphics, nodeColor,
activityType);
} finally {
graphics.dispose();
}
}

/**
* 标记历史节点
*
* @param image
* 原始图片
* @param x
* 左上角节点坐在X位置
* @param y
* 左上角节点坐在Y位置
* @param width
* 宽
* @param height
* 高
* @param activityType
* 节点类型
*/
private static void signHistoryNode(BufferedImage image, int x, int y,
int width, int height, String activityType) {
Color nodeColor = HISTORY_COLOR;
Graphics2D graphics = image.createGraphics();

try {
drawNodeBorder(x, y, width, height, graphics, nodeColor,
activityType);
} finally {
graphics.dispose();
}
}

private static void signSkipNode(BufferedImage image, int x, int y,
int width, int height, String activityType) {
Color nodeColor = SKIP_COLOR;
Graphics2D graphics = image.createGraphics();

try {
drawNodeBorder(x, y, width, height, graphics, nodeColor,
activityType);
} finally {
graphics.dispose();
}
}

/**
* 绘制节点边框
*
* @param x
* 左上角节点坐在X位置
* @param y
* 左上角节点坐在Y位置
* @param width
* 宽
* @param height
* 高
* @param graphics
* 绘图对象
* @param color
* 节点边框颜色
* @param activityType
* 节点类型
*/
protected static void drawNodeBorder(int x, int y, int width, int height,
Graphics2D graphics, Color color, String activityType) {
graphics.setPaint(color);
graphics.setStroke(THICK_BORDER_STROKE);

if (taskType.contains(activityType)) {
drawTask(x, y, width, height, graphics);
} else if (gatewayType.contains(activityType)) {
drawGateway(x, y, width, height, graphics);
} else if (eventType.contains(activityType)) {
drawEvent(x, y, width, height, graphics);
} else if (subProcessType.contains(activityType)) {
drawSubProcess(x, y, width, height, graphics);
}
}

/**
* 绘制任务
*/
protected static void drawTask(int x, int y, int width, int height,
Graphics2D graphics) {
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width,
height, OFFSET_TASK, OFFSET_TASK);
graphics.draw(rect);
}

/**
* 绘制网关
*/
protected static void drawGateway(int x, int y, int width, int height,
Graphics2D graphics) {
Polygon rhombus = new Polygon();
rhombus.addPoint(x, y + (height / 2));
rhombus.addPoint(x + (width / 2), y + height);
rhombus.addPoint(x + width, y + (height / 2));
rhombus.addPoint(x + (width / 2), y);
graphics.draw(rhombus);
}

/**
* 绘制任务
*/
protected static void drawEvent(int x, int y, int width, int height,
Graphics2D graphics) {
Double circle = new Ellipse2D.Double(x, y, width, height);
graphics.draw(circle);
}

/**
* 绘制子流程
*/
protected static void drawSubProcess(int x, int y, int width, int height,
Graphics2D graphics) {
RoundRectangle2D rect = new RoundRectangle2D.Double(x + 1, y + 1,
width - 2, height - 2, OFFSET_SUBPROCESS, OFFSET_SUBPROCESS);
graphics.draw(rect);
}

protected Point getMinXAndMinY(BpmnModel bpmnModel) {
// We need to calculate maximum values to know how big the image will be in its entirety
double theMinX = java.lang.Double.MAX_VALUE;
double theMaxX = 0;
double theMinY = java.lang.Double.MAX_VALUE;
double theMaxY = 0;

for (Pool pool : bpmnModel.getPools()) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
theMinX = graphicInfo.getX();
theMaxX = graphicInfo.getX() + graphicInfo.getWidth();
theMinY = graphicInfo.getY();
theMaxY = graphicInfo.getY() + graphicInfo.getHeight();
}

List flowNodes = gatherAllFlowNodes(bpmnModel);

for (FlowNode flowNode : flowNodes) {
GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(flowNode
.getId());

// width
if ((flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth()) > theMaxX) {
theMaxX = flowNodeGraphicInfo.getX()
+ flowNodeGraphicInfo.getWidth();
}

if (flowNodeGraphicInfo.getX() < theMinX) {
theMinX = flowNodeGraphicInfo.getX();
}

// height
if ((flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight()) > theMaxY) {
theMaxY = flowNodeGraphicInfo.getY()
+ flowNodeGraphicInfo.getHeight();
}

if (flowNodeGraphicInfo.getY() < theMinY) {
theMinY = flowNodeGraphicInfo.getY();
}

for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
List graphicInfoList = bpmnModel
.getFlowLocationGraphicInfo(sequenceFlow.getId());

for (GraphicInfo graphicInfo : graphicInfoList) {
// width
if (graphicInfo.getX() > theMaxX) {
theMaxX = graphicInfo.getX();
}

if (graphicInfo.getX() < theMinX) {
theMinX = graphicInfo.getX();
}

// height
if (graphicInfo.getY() > theMaxY) {
theMaxY = graphicInfo.getY();
}

if (graphicInfo.getY() < theMinY) {
theMinY = graphicInfo.getY();
}
}
}
}

List artifacts = gatherAllArtifacts(bpmnModel);

for (Artifact artifact : artifacts) {
GraphicInfo artifactGraphicInfo = bpmnModel.getGraphicInfo(artifact
.getId());

if (artifactGraphicInfo != null) {
// width
if ((artifactGraphicInfo.getX() + artifactGraphicInfo
.getWidth()) > theMaxX) {
theMaxX = artifactGraphicInfo.getX()
+ artifactGraphicInfo.getWidth();
}

if (artifactGraphicInfo.getX() < theMinX) {
theMinX = artifactGraphicInfo.getX();
}

// height
if ((artifactGraphicInfo.getY() + artifactGraphicInfo
.getHeight()) > theMaxY) {
theMaxY = artifactGraphicInfo.getY()
+ artifactGraphicInfo.getHeight();
}

if (artifactGraphicInfo.getY() < theMinY) {
theMinY = artifactGraphicInfo.getY();
}
}

List graphicInfoList = bpmnModel
.getFlowLocationGraphicInfo(artifact.getId());

if (graphicInfoList != null) {
for (GraphicInfo graphicInfo : graphicInfoList) {
// width
if (graphicInfo.getX() > theMaxX) {
theMaxX = graphicInfo.getX();
}

if (graphicInfo.getX() < theMinX) {
theMinX = graphicInfo.getX();
}

// height
if (graphicInfo.getY() > theMaxY) {
theMaxY = graphicInfo.getY();
}

if (graphicInfo.getY() < theMinY) {
theMinY = graphicInfo.getY();
}
}
}
}

int nrOfLanes = 0;

for (org.activiti.bpmn.model.Process process : bpmnModel.getProcesses()) {
for (Lane l : process.getLanes()) {
nrOfLanes++;

GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(l.getId());

// // width
if ((graphicInfo.getX() + graphicInfo.getWidth()) > theMaxX) {
theMaxX = graphicInfo.getX() + graphicInfo.getWidth();
}

if (graphicInfo.getX() < theMinX) {
theMinX = graphicInfo.getX();
}

// height
if ((graphicInfo.getY() + graphicInfo.getHeight()) > theMaxY) {
theMaxY = graphicInfo.getY() + graphicInfo.getHeight();
}

if (graphicInfo.getY() < theMinY) {
theMinY = graphicInfo.getY();
}
}
}

// Special case, see http://jira.codehaus.org/browse/ACT-1431
if ((flowNodes.size() == 0) && (bpmnModel.getPools().size() == 0)
&& (nrOfLanes == 0)) {
// Nothing to show
theMinX = 0;
theMinY = 0;
}

return new Point((int) theMinX, (int) theMinY);
}

protected static List gatherAllArtifacts(BpmnModel bpmnModel) {
List artifacts = new ArrayList();

for (org.activiti.bpmn.model.Process process : bpmnModel.getProcesses()) {
artifacts.addAll(process.getArtifacts());
}

return artifacts;
}

protected static List gatherAllFlowNodes(BpmnModel bpmnModel) {
List flowNodes = new ArrayList();

for (org.activiti.bpmn.model.Process process : bpmnModel.getProcesses()) {
flowNodes.addAll(gatherAllFlowNodes(process));
}

return flowNodes;
}

protected static List gatherAllFlowNodes(
FlowElementsContainer flowElementsContainer) {
List flowNodes = new ArrayList();

for (FlowElement flowElement : flowElementsContainer.getFlowElements()) {
if (flowElement instanceof FlowNode) {
flowNodes.add((FlowNode) flowElement);
}

if (flowElement instanceof FlowElementsContainer) {
flowNodes
.addAll(gatherAllFlowNodes((FlowElementsContainer) flowElement));
}
}

return flowNodes;
}

public void drawHistoryFlow(BufferedImage image, String processInstanceId) {
HistoricProcessInstance historicProcessInstance = Context
.getCommandContext().getHistoricProcessInstanceEntityManager()
.findHistoricProcessInstance(processInstanceId);
String processDefinitionId = historicProcessInstance
.getProcessDefinitionId();
Graph graph = new ActivitiHistoryGraphBuilder(processInstanceId)
.build();

for (Edge edge : graph.getEdges()) {
drawSequenceFlow(image, processDefinitionId, edge.getName());
}
}

public void drawSequenceFlow(BufferedImage image,
String processDefinitionId, String sequenceFlowId) {
GetBpmnModelCmd getBpmnModelCmd = new GetBpmnModelCmd(
processDefinitionId);
BpmnModel bpmnModel = getBpmnModelCmd.execute(Context
.getCommandContext());

Graphics2D graphics = image.createGraphics();
graphics.setPaint(HISTORY_COLOR);
graphics.setStroke(new BasicStroke(2f));

try {
List graphicInfoList = bpmnModel
.getFlowLocationGraphicInfo(sequenceFlowId);

int[] xPoints = new int[graphicInfoList.size()];
int[] yPoints = new int[graphicInfoList.size()];

for (int i = 1; i < graphicInfoList.size(); i++) {
GraphicInfo graphicInfo = graphicInfoList.get(i);
GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1);

if (i == 1) {
xPoints[0] = (int) previousGraphicInfo.getX();
yPoints[0] = (int) previousGraphicInfo.getY();
}

xPoints[i] = (int) graphicInfo.getX();
yPoints[i] = (int) graphicInfo.getY();
}

int radius = 15;

Path2D path = new Path2D.Double();

for (int i = 0; i < xPoints.length; i++) {
Integer anchorX = xPoints[i];
Integer anchorY = yPoints[i];

double targetX = anchorX;
double targetY = anchorY;

double ax = 0;
double ay = 0;
double bx = 0;
double by = 0;
double zx = 0;
double zy = 0;

if ((i > 0) && (i < (xPoints.length - 1))) {
Integer cx = anchorX;
Integer cy = anchorY;

// pivot point of prev line
double lineLengthY = yPoints[i] - yPoints[i - 1];

// pivot point of prev line
double lineLengthX = xPoints[i] - xPoints[i - 1];
double lineLength = Math.sqrt(Math.pow(lineLengthY, 2)
+ Math.pow(lineLengthX, 2));
double dx = (lineLengthX * radius) / lineLength;
double dy = (lineLengthY * radius) / lineLength;
targetX = targetX - dx;
targetY = targetY - dy;

// isDefaultConditionAvailable = isDefault && i == 1 && lineLength > 10;
if ((lineLength < (2 * radius)) && (i > 1)) {
targetX = xPoints[i] - (lineLengthX / 2);
targetY = yPoints[i] - (lineLengthY / 2);
}

// pivot point of next line
lineLengthY = yPoints[i + 1] - yPoints[i];
lineLengthX = xPoints[i + 1] - xPoints[i];
lineLength = Math.sqrt(Math.pow(lineLengthY, 2)
+ Math.pow(lineLengthX, 2));

if (lineLength < radius) {
lineLength = radius;
}

dx = (lineLengthX * radius) / lineLength;
dy = (lineLengthY * radius) / lineLength;

double nextSrcX = xPoints[i] + dx;
double nextSrcY = yPoints[i] + dy;

if ((lineLength < (2 * radius))
&& (i < (xPoints.length - 2))) {
nextSrcX = xPoints[i] + (lineLengthX / 2);
nextSrcY = yPoints[i] + (lineLengthY / 2);
}

double dx0 = (cx - targetX) / 3;
double dy0 = (cy - targetY) / 3;
ax = cx - dx0;
ay = cy - dy0;

double dx1 = (cx - nextSrcX) / 3;
double dy1 = (cy - nextSrcY) / 3;
bx = cx - dx1;
by = cy - dy1;

zx = nextSrcX;
zy = nextSrcY;
}

if (i == 0) {
path.moveTo(targetX, targetY);
} else {
path.lineTo(targetX, targetY);
}

if ((i > 0) && (i < (xPoints.length - 1))) {
// add curve
path.curveTo(ax, ay, bx, by, zx, zy);
}
}

graphics.draw(path);

// draw arrow
Line2D.Double line = new Line2D.Double(xPoints[xPoints.length - 2],
yPoints[xPoints.length - 2], xPoints[xPoints.length - 1],
yPoints[xPoints.length - 1]);

int ARROW_WIDTH = 5;
int doubleArrowWidth = 2 * ARROW_WIDTH;
Polygon arrowHead = new Polygon();
arrowHead.addPoint(0, 0);
arrowHead.addPoint(-ARROW_WIDTH, -doubleArrowWidth);
arrowHead.addPoint(ARROW_WIDTH, -doubleArrowWidth);

AffineTransform transformation = new AffineTransform();
transformation.setToIdentity();

double angle = Math.atan2(line.y2 - line.y1, line.x2 - line.x1);
transformation.translate(line.x2, line.y2);
transformation.rotate((angle - (Math.PI / 2d)));

AffineTransform originalTransformation = graphics.getTransform();
graphics.setTransform(transformation);
graphics.fill(arrowHead);
graphics.setTransform(originalTransformation);
} finally {
graphics.dispose();
}
}
}

Graph.java

package com.plate.bpm.graph;

import java.util.ArrayList;
import java.util.List;


public class Graph {
private Node initial;

public Node getInitial() {
return initial;
}

public void setInitial(Node initial) {
this.initial = initial;
}

public List getNodes() {
List nodes = new ArrayList();
visitNode(initial, nodes);

return nodes;
}

public void visitNode(Node node, List nodes) {
nodes.add(node);

for (Edge edge : node.getOutgoingEdges()) {
Node nextNode = edge.getDest();
visitNode(nextNode, nodes);
}
}

public List getEdges() {
List edges = new ArrayList();
visitEdge(initial, edges);

return edges;
}

public void visitEdge(Node node, List edges) {
for (Edge edge : node.getOutgoingEdges()) {
edges.add(edge);

Node nextNode = edge.getDest();
visitEdge(nextNode, edges);
}
}

public Node findById(String id) {
for (Node node : this.getNodes()) {
if (id.equals(node.getId())) {
return node;
}
}

return null;
}
}


GraphElement.java

package com.plate.bpm.graph;


/**
* 节点和连线的父类.
*/
public class GraphElement {
/**
* 实例id,历史的id.
*/
private String id;

/**
* 节点名称,bpmn图形中的id.
*/
private String name;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}



Edge.java

package com.plate.bpm.graph;


/**
* 连线.
*/
public class Edge extends GraphElement {
/**
* 起点.
*/
private Node src;

/**
* 终点.
*/
private Node dest;

/**
* 循环.
*/
private boolean cycle;

public Node getSrc() {
return src;
}

public void setSrc(Node src) {
this.src = src;
}

public Node getDest() {
return dest;
}

public void setDest(Node dest) {
this.dest = dest;
}

public boolean isCycle() {
return cycle;
}

public void setCycle(boolean cycle) {
this.cycle = cycle;
}
}

ActivitiHistoryGraphBuilder.java
package com.plate.bpm.graph;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.impl.HistoricActivityInstanceQueryImpl;
import org.activiti.engine.impl.Page;
import org.activiti.engine.impl.cmd.GetDeploymentProcessDefinitionCmd;
import org.activiti.engine.impl.context.Context;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
* 根据历史,生成实时运行阶段的子图.
*/
public class ActivitiHistoryGraphBuilder {
/**
* logger.
*/
private static Logger logger = LoggerFactory
.getLogger(ActivitiHistoryGraphBuilder.class);
private String processInstanceId;
private ProcessDefinitionEntity processDefinitionEntity;
private List historicActivityInstances;
private List visitedHistoricActivityInstances = new ArrayList();
private Map nodeMap = new HashMap();

public ActivitiHistoryGraphBuilder(String processInstanceId) {
this.processInstanceId = processInstanceId;
}

public Graph build() {
this.fetchProcessDefinitionEntity();
this.fetchHistoricActivityInstances();

Graph graph = new Graph();

for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
Node currentNode = new Node();
currentNode.setId(historicActivityInstance.getId());
currentNode.setName(historicActivityInstance.getActivityId());
currentNode.setType(historicActivityInstance.getActivityType());
currentNode
.setActive(historicActivityInstance.getEndTime() == null);
logger.debug("currentNode : {}:{}", currentNode.getName(),
currentNode.getId());

Edge previousEdge = this.findPreviousEdge(currentNode,
historicActivityInstance.getStartTime().getTime());

if (previousEdge == null) {
if (graph.getInitial() != null) {
throw new IllegalStateException("already set an initial.");
}

graph.setInitial(currentNode);
} else {
logger.debug("previousEdge : {}", previousEdge.getName());
}

nodeMap.put(currentNode.getId(), currentNode);
visitedHistoricActivityInstances.add(historicActivityInstance);
}

if (graph.getInitial() == null) {
throw new IllegalStateException("cannot find initial.");
}

return graph;
}

/**
* 根据流程实例id获取对应的流程定义.
*/
public void fetchProcessDefinitionEntity() {
String processDefinitionId = Context.getCommandContext()
.getHistoricProcessInstanceEntityManager()
.findHistoricProcessInstance(processInstanceId)
.getProcessDefinitionId();
GetDeploymentProcessDefinitionCmd cmd = new GetDeploymentProcessDefinitionCmd(
processDefinitionId);
processDefinitionEntity = cmd.execute(Context.getCommandContext());
}

public void fetchHistoricActivityInstances() {
HistoricActivityInstanceQueryImpl historicActivityInstanceQueryImpl = new HistoricActivityInstanceQueryImpl();
// historicActivityInstanceQueryImpl.processInstanceId(processInstanceId)
// .orderByHistoricActivityInstanceStartTime().asc();
// TODO: 如果用了uuid会造成这样排序出问题
// 但是如果用startTime,可能出现因为处理速度太快,时间一样,导致次序颠倒的问题
historicActivityInstanceQueryImpl.processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceId().asc();

Page page = new Page(0, 100);
historicActivityInstances = Context
.getCommandContext()
.getHistoricActivityInstanceEntityManager()
.findHistoricActivityInstancesByQueryCriteria(
historicActivityInstanceQueryImpl, page);
}

/**
* 找到这个节点前面的连线.
*/
public Edge findPreviousEdge(Node currentNode, long currentStartTime) {
String activityId = currentNode.getName();
ActivityImpl activityImpl = processDefinitionEntity
.findActivity(activityId);
HistoricActivityInstance nestestHistoricActivityInstance = null;
String temporaryPvmTransitionId = null;

// 遍历进入当前节点的所有连线
for (PvmTransition pvmTransition : activityImpl
.getIncomingTransitions()) {
PvmActivity source = pvmTransition.getSource();

String previousActivityId = source.getId();

HistoricActivityInstance visitiedHistoryActivityInstance = this
.findVisitedHistoricActivityInstance(previousActivityId);

if (visitiedHistoryActivityInstance == null) {
continue;
}

// 如果上一个节点还未完成,说明不可能是从这个节点过来的,跳过
if (visitiedHistoryActivityInstance.getEndTime() == null) {
continue;
}

logger.debug("current activity start time : {}", new Date(
currentStartTime));
logger.debug("nestest activity end time : {}",
visitiedHistoryActivityInstance.getEndTime());

// 如果当前节点的开始时间,比上一个节点的结束时间要早,跳过
if (currentStartTime < visitiedHistoryActivityInstance.getEndTime()
.getTime()) {
continue;
}

if (nestestHistoricActivityInstance == null) {
nestestHistoricActivityInstance = visitiedHistoryActivityInstance;
temporaryPvmTransitionId = pvmTransition.getId();
} else if ((currentStartTime - nestestHistoricActivityInstance
.getEndTime().getTime()) > (currentStartTime - visitiedHistoryActivityInstance
.getEndTime().getTime())) {
// 寻找离当前节点最近的上一个节点
// 比较上一个节点的endTime与当前节点startTime的差
nestestHistoricActivityInstance = visitiedHistoryActivityInstance;
temporaryPvmTransitionId = pvmTransition.getId();
}
}

// 没找到上一个节点,就返回null
if (nestestHistoricActivityInstance == null) {
return null;
}

Node previousNode = nodeMap
.get(nestestHistoricActivityInstance.getId());

if (previousNode == null) {
return null;
}

logger.debug("previousNode : {}:{}", previousNode.getName(),
previousNode.getId());

Edge edge = new Edge();
edge.setName(temporaryPvmTransitionId);
previousNode.getOutgoingEdges().add(edge);
edge.setSrc(previousNode);
edge.setDest(currentNode);

return edge;
}

public HistoricActivityInstance findVisitedHistoricActivityInstance(
String activityId) {
for (int i = visitedHistoricActivityInstances.size() - 1; i >= 0; i--) {
HistoricActivityInstance historicActivityInstance = visitedHistoricActivityInstances
.get(i);

if (activityId.equals(historicActivityInstance.getActivityId())) {
return historicActivityInstance;
}
}

return null;
}
}

ActivitiGraphBuilder.java
package com.plate.bpm.graph;

import java.util.HashSet;
import java.util.Set;

import org.activiti.engine.impl.cmd.GetDeploymentProcessDefinitionCmd;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;

/**
* 根据流程定义,构建设计阶段的图.
*/
public class ActivitiGraphBuilder {
/**
* 流程定义id.
*/
private String processDefinitionId;

/**
* 流程定义.
*/
private ProcessDefinitionEntity processDefinitionEntity;

/**
* 已访问的节点id.
*/
private Set visitedNodeIds = new HashSet();

/**
* 构造方法.
*/
public ActivitiGraphBuilder(String processDefinitionId) {
this.processDefinitionId = processDefinitionId;
}

/**
* 构建图.
*/
public Graph build() {
this.fetchProcessDefinitionEntity();

Node initial = visitNode(processDefinitionEntity.getInitial());

Graph graph = new Graph();
graph.setInitial(initial);

return graph;
}

/**
* 获取流程定义.
*/
public void fetchProcessDefinitionEntity() {
GetDeploymentProcessDefinitionCmd cmd = new GetDeploymentProcessDefinitionCmd(
processDefinitionId);
processDefinitionEntity = cmd.execute(Context.getCommandContext());
}

/**
* 遍历.
*/
public Node visitNode(PvmActivity pvmActivity) {
if (visitedNodeIds.contains(pvmActivity.getId())) {
return null;
}

visitedNodeIds.add(pvmActivity.getId());

Node currentNode = new Node();
currentNode.setId(pvmActivity.getId());
currentNode.setName(this.getString(pvmActivity.getProperty("name")));
currentNode.setType(this.getString(pvmActivity.getProperty("type")));

for (PvmTransition pvmTransition : pvmActivity.getOutgoingTransitions()) {
PvmActivity destination = pvmTransition.getDestination();
Node targetNode = this.visitNode(destination);

if (targetNode == null) {
continue;
}

Edge edge = new Edge();
edge.setId(pvmTransition.getId());
edge.setSrc(currentNode);
edge.setDest(targetNode);
currentNode.getOutgoingEdges().add(edge);
}

return currentNode;
}

/**
* 把object转换为string.
*/
public String getString(Object object) {
if (object == null) {
return null;
} else if (object instanceof String) {
return (String) object;
} else {
return object.toString();
}
}
}

Node.java
package com.plate.bpm.graph;

import java.util.ArrayList;
import java.util.List;


/**
* 节点.
*/
public class Node extends GraphElement {
/**
* 类型,比如userTask,startEvent.
*/
private String type;

/**
* 是否还未完成.
*/
private boolean active;

/**
* 进入这个节点的所有连线.
*/
private List incomingEdges = new ArrayList();

/**
* 外出这个节点的所有连线.
*/
private List outgoingEdges = new ArrayList();

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

public boolean isActive() {
return active;
}

public void setActive(boolean active) {
this.active = active;
}

public List getIncomingEdges() {
return incomingEdges;
}

public void setIncomingEdges(List incomingEdges) {
this.incomingEdges = incomingEdges;
}

public List getOutgoingEdges() {
return outgoingEdges;
}

public void setOutgoingEdges(List outgoingEdges) {
this.outgoingEdges = outgoingEdges;
}
}

希望对你有所帮助,如果有更好的办法记得分享给大家哦!

你可能感兴趣的:(activiti,activiti,java,spring,mvc)