com.haoxuer.discover.activiti.controller.services.BaseProcessDefinitionDiagramLayoutResource Maven / Gradle / Ivy
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.haoxuer.discover.activiti.controller.services;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.impl.bpmn.behavior.BoundaryEventActivityBehavior;
import org.activiti.engine.impl.bpmn.behavior.CallActivityBehavior;
import org.activiti.engine.impl.bpmn.parser.BpmnParse;
import org.activiti.engine.impl.bpmn.parser.ErrorEventDefinition;
import org.activiti.engine.impl.bpmn.parser.EventSubscriptionDeclaration;
import org.activiti.engine.impl.jobexecutor.TimerDeclarationImpl;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.delegate.ActivityBehavior;
import org.activiti.engine.impl.pvm.process.*;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.*;
public class BaseProcessDefinitionDiagramLayoutResource {
@Autowired
private RuntimeService runtimeService;
@Autowired
private RepositoryService repositoryService;
@Autowired
private HistoryService historyService;
public ObjectNode getDiagramNode(String processInstanceId, String processDefinitionId) {
List highLightedFlows = Collections. emptyList();
List highLightedActivities = Collections. emptyList();
Map subProcessInstanceMap = new HashMap();
ProcessInstance processInstance = null;
if (processInstanceId != null) {
processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
if (processInstance == null) {
throw new ActivitiObjectNotFoundException("Process instance could not be found");
}
processDefinitionId = processInstance.getProcessDefinitionId();
List subProcessInstances = runtimeService.createProcessInstanceQuery().superProcessInstanceId(processInstanceId).list();
for (ProcessInstance subProcessInstance : subProcessInstances) {
String subDefId = subProcessInstance.getProcessDefinitionId();
String superExecutionId = ((ExecutionEntity) subProcessInstance).getSuperExecutionId();
ProcessDefinitionEntity subDef = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(subDefId);
ObjectNode processInstanceJSON = new ObjectMapper().createObjectNode();
processInstanceJSON.put("processInstanceId", subProcessInstance.getId());
processInstanceJSON.put("superExecutionId", superExecutionId);
processInstanceJSON.put("processDefinitionId", subDef.getId());
processInstanceJSON.put("processDefinitionKey", subDef.getKey());
processInstanceJSON.put("processDefinitionName", subDef.getName());
subProcessInstanceMap.put(superExecutionId, processInstanceJSON);
}
}
if (processDefinitionId == null) {
throw new ActivitiObjectNotFoundException("No process definition id provided");
}
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(processDefinitionId);
if (processDefinition == null) {
throw new ActivitiException("Process definition " + processDefinitionId + " could not be found");
}
ObjectNode responseJSON = new ObjectMapper().createObjectNode();
// Process definition
JsonNode pdrJSON = getProcessDefinitionResponse(processDefinition);
if (pdrJSON != null) {
responseJSON.put("processDefinition", pdrJSON);
}
// Highlighted activities
if (processInstance != null) {
ArrayNode activityArray = new ObjectMapper().createArrayNode();
ArrayNode flowsArray = new ObjectMapper().createArrayNode();
highLightedActivities = runtimeService.getActiveActivityIds(processInstanceId);
highLightedFlows = getHighLightedFlows(processInstanceId, processDefinition);
for (String activityName : highLightedActivities) {
activityArray.add(activityName);
}
for (String flow : highLightedFlows)
flowsArray.add(flow);
responseJSON.put("highLightedActivities", activityArray);
responseJSON.put("highLightedFlows", flowsArray);
}
// Pool shape, if process is participant in collaboration
if (processDefinition.getParticipantProcess() != null) {
ParticipantProcess pProc = processDefinition.getParticipantProcess();
ObjectNode participantProcessJSON = new ObjectMapper().createObjectNode();
participantProcessJSON.put("id", pProc.getId());
if (StringUtils.isNotEmpty(pProc.getName())) {
participantProcessJSON.put("name", pProc.getName());
} else {
participantProcessJSON.put("name", "");
}
participantProcessJSON.put("x", pProc.getX());
participantProcessJSON.put("y", pProc.getY());
participantProcessJSON.put("width", pProc.getWidth());
participantProcessJSON.put("height", pProc.getHeight());
responseJSON.put("participantProcess", participantProcessJSON);
}
// Draw lanes
if (processDefinition.getLaneSets() != null && !processDefinition.getLaneSets().isEmpty()) {
ArrayNode laneSetArray = new ObjectMapper().createArrayNode();
for (LaneSet laneSet : processDefinition.getLaneSets()) {
ArrayNode laneArray = new ObjectMapper().createArrayNode();
if (laneSet.getLanes() != null && !laneSet.getLanes().isEmpty()) {
for (Lane lane : laneSet.getLanes()) {
ObjectNode laneJSON = new ObjectMapper().createObjectNode();
laneJSON.put("id", lane.getId());
if (StringUtils.isNotEmpty(lane.getName())) {
laneJSON.put("name", lane.getName());
} else {
laneJSON.put("name", "");
}
laneJSON.put("x", lane.getX());
laneJSON.put("y", lane.getY());
laneJSON.put("width", lane.getWidth());
laneJSON.put("height", lane.getHeight());
List flowNodeIds = lane.getFlowNodeIds();
ArrayNode flowNodeIdsArray = new ObjectMapper().createArrayNode();
for (String flowNodeId : flowNodeIds) {
flowNodeIdsArray.add(flowNodeId);
}
laneJSON.put("flowNodeIds", flowNodeIdsArray);
laneArray.add(laneJSON);
}
}
ObjectNode laneSetJSON = new ObjectMapper().createObjectNode();
laneSetJSON.put("id", laneSet.getId());
if (StringUtils.isNotEmpty(laneSet.getName())) {
laneSetJSON.put("name", laneSet.getName());
} else {
laneSetJSON.put("name", "");
}
laneSetJSON.put("lanes", laneArray);
laneSetArray.add(laneSetJSON);
}
if (laneSetArray.size() > 0)
responseJSON.put("laneSets", laneSetArray);
}
ArrayNode sequenceFlowArray = new ObjectMapper().createArrayNode();
ArrayNode activityArray = new ObjectMapper().createArrayNode();
// Activities and their sequence-flows
for (ActivityImpl activity : processDefinition.getActivities()) {
getActivity(processInstanceId, activity, activityArray, sequenceFlowArray, processInstance, highLightedFlows, subProcessInstanceMap);
}
responseJSON.put("activities", activityArray);
responseJSON.put("sequenceFlows", sequenceFlowArray);
return responseJSON;
}
private List getHighLightedFlows(String processInstanceId, ProcessDefinitionEntity processDefinition) {
List highLightedFlows = new ArrayList();
List historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();
List historicActivityInstanceList = new ArrayList();
for (HistoricActivityInstance hai : historicActivityInstances) {
historicActivityInstanceList.add(hai.getActivityId());
}
// add current activities to list
List highLightedActivities = runtimeService.getActiveActivityIds(processInstanceId);
historicActivityInstanceList.addAll(highLightedActivities);
// activities and their sequence-flows
for (ActivityImpl activity : processDefinition.getActivities()) {
int index = historicActivityInstanceList.indexOf(activity.getId());
if (index >= 0 && index + 1 < historicActivityInstanceList.size()) {
List pvmTransitionList = activity.getOutgoingTransitions();
for (PvmTransition pvmTransition : pvmTransitionList) {
String destinationFlowId = pvmTransition.getDestination().getId();
if (destinationFlowId.equals(historicActivityInstanceList.get(index + 1))) {
highLightedFlows.add(pvmTransition.getId());
}
}
}
}
return highLightedFlows;
}
private void getActivity(String processInstanceId, ActivityImpl activity, ArrayNode activityArray, ArrayNode sequenceFlowArray,
ProcessInstance processInstance, List highLightedFlows, Map subProcessInstanceMap) {
ObjectNode activityJSON = new ObjectMapper().createObjectNode();
// Gather info on the multi instance marker
String multiInstance = (String) activity.getProperty("multiInstance");
if (multiInstance != null) {
if (!"sequential".equals(multiInstance)) {
multiInstance = "parallel";
}
}
ActivityBehavior activityBehavior = activity.getActivityBehavior();
// Gather info on the collapsed marker
Boolean collapsed = (activityBehavior instanceof CallActivityBehavior);
Boolean expanded = (Boolean) activity.getProperty(BpmnParse.PROPERTYNAME_ISEXPANDED);
if (expanded != null) {
collapsed = !expanded;
}
Boolean isInterrupting = null;
if (activityBehavior instanceof BoundaryEventActivityBehavior) {
isInterrupting = ((BoundaryEventActivityBehavior) activityBehavior).isInterrupting();
}
// Outgoing transitions of activity
for (PvmTransition sequenceFlow : activity.getOutgoingTransitions()) {
String flowName = (String) sequenceFlow.getProperty("name");
boolean isHighLighted = (highLightedFlows.contains(sequenceFlow.getId()));
boolean isConditional = sequenceFlow.getProperty(BpmnParse.PROPERTYNAME_CONDITION) != null
&& !((String) activity.getProperty("type")).toLowerCase().contains("gateway");
boolean isDefault = sequenceFlow.getId().equals(activity.getProperty("default"))
&& ((String) activity.getProperty("type")).toLowerCase().contains("gateway");
List waypoints = ((TransitionImpl) sequenceFlow).getWaypoints();
ArrayNode xPointArray = new ObjectMapper().createArrayNode();
ArrayNode yPointArray = new ObjectMapper().createArrayNode();
for (int i = 0; i < waypoints.size(); i += 2) { // waypoints.size()
// minimally 4: x1, y1,
// x2, y2
xPointArray.add(waypoints.get(i));
yPointArray.add(waypoints.get(i + 1));
}
ObjectNode flowJSON = new ObjectMapper().createObjectNode();
flowJSON.put("id", sequenceFlow.getId());
flowJSON.put("name", flowName);
flowJSON.put("flow", "(" + sequenceFlow.getSource().getId() + ")--" + sequenceFlow.getId() + "-->("
+ sequenceFlow.getDestination().getId() + ")");
if (isConditional)
flowJSON.put("isConditional", isConditional);
if (isDefault)
flowJSON.put("isDefault", isDefault);
if (isHighLighted)
flowJSON.put("isHighLighted", isHighLighted);
flowJSON.put("xPointArray", xPointArray);
flowJSON.put("yPointArray", yPointArray);
sequenceFlowArray.add(flowJSON);
}
// Nested activities (boundary events)
ArrayNode nestedActivityArray = new ObjectMapper().createArrayNode();
for (ActivityImpl nestedActivity : activity.getActivities()) {
nestedActivityArray.add(nestedActivity.getId());
}
Map properties = activity.getProperties();
ObjectNode propertiesJSON = new ObjectMapper().createObjectNode();
for (String key : properties.keySet()) {
Object prop = properties.get(key);
if (prop instanceof String)
propertiesJSON.put(key, (String) properties.get(key));
else if (prop instanceof Integer)
propertiesJSON.put(key, (Integer) properties.get(key));
else if (prop instanceof Boolean)
propertiesJSON.put(key, (Boolean) properties.get(key));
else if ("initial".equals(key)) {
ActivityImpl act = (ActivityImpl) properties.get(key);
propertiesJSON.put(key, act.getId());
} else if ("timerDeclarations".equals(key)) {
ArrayList timerDeclarations = (ArrayList) properties.get(key);
ArrayNode timerDeclarationArray = new ObjectMapper().createArrayNode();
if (timerDeclarations != null)
for (TimerDeclarationImpl timerDeclaration : timerDeclarations) {
ObjectNode timerDeclarationJSON = new ObjectMapper().createObjectNode();
timerDeclarationJSON.put("isExclusive", timerDeclaration.isExclusive());
if (timerDeclaration.getRepeat() != null)
timerDeclarationJSON.put("repeat", timerDeclaration.getRepeat());
timerDeclarationJSON.put("retries", String.valueOf(timerDeclaration.getRetries()));
timerDeclarationJSON.put("type", timerDeclaration.getJobHandlerType());
timerDeclarationJSON.put("configuration", timerDeclaration.getJobHandlerConfiguration());
//timerDeclarationJSON.put("expression", timerDeclaration.getDescription());
timerDeclarationArray.add(timerDeclarationJSON);
}
if (timerDeclarationArray.size() > 0)
propertiesJSON.put(key, timerDeclarationArray);
// TODO: implement getting description
} else if ("eventDefinitions".equals(key)) {
ArrayList eventDefinitions = (ArrayList) properties.get(key);
ArrayNode eventDefinitionsArray = new ObjectMapper().createArrayNode();
if (eventDefinitions != null) {
for (EventSubscriptionDeclaration eventDefinition : eventDefinitions) {
ObjectNode eventDefinitionJSON = new ObjectMapper().createObjectNode();
if (eventDefinition.getActivityId() != null)
eventDefinitionJSON.put("activityId", eventDefinition.getActivityId());
eventDefinitionJSON.put("eventName", eventDefinition.getEventName());
eventDefinitionJSON.put("eventType", eventDefinition.getEventType());
eventDefinitionJSON.put("isAsync", eventDefinition.isAsync());
eventDefinitionJSON.put("isStartEvent", eventDefinition.isStartEvent());
eventDefinitionsArray.add(eventDefinitionJSON);
}
}
if (eventDefinitionsArray.size() > 0)
propertiesJSON.put(key, eventDefinitionsArray);
// TODO: implement it
} else if ("errorEventDefinitions".equals(key)) {
ArrayList errorEventDefinitions = (ArrayList) properties.get(key);
ArrayNode errorEventDefinitionsArray = new ObjectMapper().createArrayNode();
if (errorEventDefinitions != null) {
for (ErrorEventDefinition errorEventDefinition : errorEventDefinitions) {
ObjectNode errorEventDefinitionJSON = new ObjectMapper().createObjectNode();
if (errorEventDefinition.getErrorCode() != null)
errorEventDefinitionJSON.put("errorCode", errorEventDefinition.getErrorCode());
else
errorEventDefinitionJSON.putNull("errorCode");
errorEventDefinitionJSON.put("handlerActivityId", errorEventDefinition.getHandlerActivityId());
errorEventDefinitionsArray.add(errorEventDefinitionJSON);
}
}
if (errorEventDefinitionsArray.size() > 0)
propertiesJSON.put(key, errorEventDefinitionsArray);
}
}
if ("callActivity".equals(properties.get("type"))) {
CallActivityBehavior callActivityBehavior = null;
if (activityBehavior instanceof CallActivityBehavior) {
callActivityBehavior = (CallActivityBehavior) activityBehavior;
}
if (callActivityBehavior != null) {
propertiesJSON.put("processDefinitonKey", callActivityBehavior.getProcessDefinitonKey());
// get processDefinitonId from execution or get last processDefinitonId
// by key
ArrayNode processInstanceArray = new ObjectMapper().createArrayNode();
if (processInstance != null) {
List executionList = runtimeService.createExecutionQuery().processInstanceId(processInstanceId)
.activityId(activity.getId()).list();
if (!executionList.isEmpty()) {
for (Execution execution : executionList) {
ObjectNode processInstanceJSON = subProcessInstanceMap.get(execution.getId());
processInstanceArray.add(processInstanceJSON);
}
}
}
// If active activities nas no instance of this callActivity then add
// last definition
if (processInstanceArray.size() == 0 && StringUtils.isNotEmpty(callActivityBehavior.getProcessDefinitonKey())) {
// Get last definition by key
ProcessDefinition lastProcessDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey(callActivityBehavior.getProcessDefinitonKey()).latestVersion().singleResult();
// TODO: unuseful fields there are processDefinitionName, processDefinitionKey
if (lastProcessDefinition != null) {
ObjectNode processInstanceJSON = new ObjectMapper().createObjectNode();
processInstanceJSON.put("processDefinitionId", lastProcessDefinition.getId());
processInstanceJSON.put("processDefinitionKey", lastProcessDefinition.getKey());
processInstanceJSON.put("processDefinitionName", lastProcessDefinition.getName());
processInstanceArray.add(processInstanceJSON);
}
}
if (processInstanceArray.size() > 0) {
propertiesJSON.put("processDefinitons", processInstanceArray);
}
}
}
activityJSON.put("activityId", activity.getId());
activityJSON.put("properties", propertiesJSON);
if (multiInstance != null)
activityJSON.put("multiInstance", multiInstance);
if (collapsed)
activityJSON.put("collapsed", collapsed);
if (nestedActivityArray.size() > 0)
activityJSON.put("nestedActivities", nestedActivityArray);
if (isInterrupting != null)
activityJSON.put("isInterrupting", isInterrupting);
activityJSON.put("x", activity.getX());
activityJSON.put("y", activity.getY());
activityJSON.put("width", activity.getWidth());
activityJSON.put("height", activity.getHeight());
activityArray.add(activityJSON);
// Nested activities (boundary events)
for (ActivityImpl nestedActivity : activity.getActivities()) {
getActivity(processInstanceId, nestedActivity, activityArray, sequenceFlowArray, processInstance, highLightedFlows, subProcessInstanceMap);
}
}
private JsonNode getProcessDefinitionResponse(ProcessDefinitionEntity processDefinition) {
ObjectMapper mapper = new ObjectMapper();
ObjectNode pdrJSON = mapper.createObjectNode();
pdrJSON.put("id", processDefinition.getId());
pdrJSON.put("name", processDefinition.getName());
pdrJSON.put("key", processDefinition.getKey());
pdrJSON.put("version", processDefinition.getVersion());
pdrJSON.put("deploymentId", processDefinition.getDeploymentId());
pdrJSON.put("isGraphicNotationDefined", isGraphicNotationDefined(processDefinition));
return pdrJSON;
}
private boolean isGraphicNotationDefined(ProcessDefinitionEntity processDefinition) {
return ((ProcessDefinitionEntity) repositoryService.getProcessDefinition(processDefinition.getId())).isGraphicalNotationDefined();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy