Java tutorial
/* 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 org.activiti.editor.language.json.converter; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import math.geom2d.Point2D; import math.geom2d.conic.Circle2D; import math.geom2d.line.Line2D; import math.geom2d.polygon.Polyline2D; import org.activiti.bpmn.model.ActivitiListener; import org.activiti.bpmn.model.Activity; import org.activiti.bpmn.model.BaseElement; import org.activiti.bpmn.model.BoundaryEvent; import org.activiti.bpmn.model.BpmnModel; import org.activiti.bpmn.model.EventListener; import org.activiti.bpmn.model.FieldExtension; 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.ImplementationType; import org.activiti.bpmn.model.Lane; import org.activiti.bpmn.model.Pool; import org.activiti.bpmn.model.Process; import org.activiti.bpmn.model.SequenceFlow; import org.activiti.bpmn.model.SubProcess; import org.activiti.editor.constants.EditorJsonConstants; import org.activiti.editor.constants.StencilConstants; import org.activiti.editor.language.json.converter.util.JsonConverterUtil; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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; /** * @author Tijs Rademakers */ public class BpmnJsonConverter implements EditorJsonConstants, StencilConstants, ActivityProcessor { protected static final Logger LOGGER = LoggerFactory.getLogger(BpmnJsonConverter.class); protected ObjectMapper objectMapper = new ObjectMapper(); protected static Map<Class<? extends BaseElement>, Class<? extends BaseBpmnJsonConverter>> convertersToJsonMap = new HashMap<Class<? extends BaseElement>, Class<? extends BaseBpmnJsonConverter>>(); protected static Map<String, Class<? extends BaseBpmnJsonConverter>> convertersToBpmnMap = new HashMap<String, Class<? extends BaseBpmnJsonConverter>>(); static { // start and end events StartEventJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); EndEventJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); // connectors SequenceFlowJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); // task types BusinessRuleTaskJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); MailTaskJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); ManualTaskJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); ReceiveTaskJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); ScriptTaskJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); ServiceTaskJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); UserTaskJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); CallActivityJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); // gateways ExclusiveGatewayJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); InclusiveGatewayJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); ParallelGatewayJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); EventGatewayJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); // scope constructs SubProcessJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); EventSubProcessJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); // catch events CatchEventJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); // throw events ThrowEventJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); // boundary events BoundaryEventJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap); } private static final List<String> DI_CIRCLES = new ArrayList<String>(); private static final List<String> DI_RECTANGLES = new ArrayList<String>(); private static final List<String> DI_GATEWAY = new ArrayList<String>(); static { DI_CIRCLES.add(STENCIL_EVENT_START_ERROR); DI_CIRCLES.add(STENCIL_EVENT_START_MESSAGE); DI_CIRCLES.add(STENCIL_EVENT_START_NONE); DI_CIRCLES.add(STENCIL_EVENT_START_TIMER); DI_CIRCLES.add(STENCIL_EVENT_BOUNDARY_ERROR); DI_CIRCLES.add(STENCIL_EVENT_BOUNDARY_SIGNAL); DI_CIRCLES.add(STENCIL_EVENT_BOUNDARY_TIMER); DI_CIRCLES.add(STENCIL_EVENT_BOUNDARY_MESSAGE); DI_CIRCLES.add(STENCIL_EVENT_CATCH_MESSAGE); DI_CIRCLES.add(STENCIL_EVENT_CATCH_SIGNAL); DI_CIRCLES.add(STENCIL_EVENT_CATCH_TIMER); DI_CIRCLES.add(STENCIL_EVENT_THROW_NONE); DI_CIRCLES.add(STENCIL_EVENT_THROW_SIGNAL); DI_CIRCLES.add(STENCIL_EVENT_END_NONE); DI_CIRCLES.add(STENCIL_EVENT_END_ERROR); DI_RECTANGLES.add(STENCIL_CALL_ACTIVITY); DI_RECTANGLES.add(STENCIL_SUB_PROCESS); DI_RECTANGLES.add(STENCIL_EVENT_SUB_PROCESS); DI_RECTANGLES.add(STENCIL_TASK_BUSINESS_RULE); DI_RECTANGLES.add(STENCIL_TASK_MAIL); DI_RECTANGLES.add(STENCIL_TASK_MANUAL); DI_RECTANGLES.add(STENCIL_TASK_RECEIVE); DI_RECTANGLES.add(STENCIL_TASK_SCRIPT); DI_RECTANGLES.add(STENCIL_TASK_SERVICE); DI_RECTANGLES.add(STENCIL_TASK_USER); DI_GATEWAY.add(STENCIL_GATEWAY_EVENT); DI_GATEWAY.add(STENCIL_GATEWAY_EXCLUSIVE); DI_GATEWAY.add(STENCIL_GATEWAY_INCLUSIVE); DI_GATEWAY.add(STENCIL_GATEWAY_PARALLEL); } public ObjectNode convertToJson(BpmnModel model) { ObjectNode modelNode = objectMapper.createObjectNode(); modelNode.put("bounds", BpmnJsonConverterUtil.createBoundsNode(1485, 1050, 0, 0)); modelNode.put("resourceId", "canvas"); ObjectNode stencilNode = objectMapper.createObjectNode(); stencilNode.put("id", "BPMNDiagram"); modelNode.put("stencil", stencilNode); ObjectNode stencilsetNode = objectMapper.createObjectNode(); stencilsetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#"); stencilsetNode.put("url", "../editor/stencilsets/bpmn2.0/bpmn2.0.json"); modelNode.put("stencilset", stencilsetNode); ArrayNode shapesArrayNode = objectMapper.createArrayNode(); Process mainProcess = model.getMainProcess(); ObjectNode propertiesNode = objectMapper.createObjectNode(); if (StringUtils.isNotEmpty(mainProcess.getId())) { propertiesNode.put(PROPERTY_PROCESS_ID, mainProcess.getId()); } if (StringUtils.isNotEmpty(mainProcess.getName())) { propertiesNode.put(PROPERTY_NAME, mainProcess.getName()); } if (mainProcess.isExecutable() == false) { propertiesNode.put(PROPERTY_PROCESS_EXECUTABLE, PROPERTY_VALUE_NO); } propertiesNode.put(PROPERTY_PROCESS_NAMESPACE, model.getTargetNamespace()); convertListenersToJson(mainProcess.getEventListeners(), propertiesNode); if (StringUtils.isNotEmpty(mainProcess.getDocumentation())) { propertiesNode.put(PROPERTY_DOCUMENTATION, mainProcess.getDocumentation()); } modelNode.put(EDITOR_SHAPE_PROPERTIES, propertiesNode); if (model.getPools().size() > 0) { for (Pool pool : model.getPools()) { GraphicInfo poolGraphicInfo = model.getGraphicInfo(pool.getId()); ObjectNode poolNode = BpmnJsonConverterUtil.createChildShape(pool.getId(), STENCIL_POOL, poolGraphicInfo.getX() + poolGraphicInfo.getWidth(), poolGraphicInfo.getY() + poolGraphicInfo.getHeight(), poolGraphicInfo.getX(), poolGraphicInfo.getY()); shapesArrayNode.add(poolNode); ObjectNode poolPropertiesNode = objectMapper.createObjectNode(); poolPropertiesNode.put(PROPERTY_OVERRIDE_ID, pool.getId()); poolPropertiesNode.put(PROPERTY_PROCESS_ID, pool.getProcessRef()); if (pool.isExecutable() == false) { poolPropertiesNode.put(PROPERTY_PROCESS_EXECUTABLE, PROPERTY_VALUE_NO); } if (StringUtils.isNotEmpty(pool.getName())) { poolPropertiesNode.put(PROPERTY_NAME, pool.getName()); } poolNode.put(EDITOR_SHAPE_PROPERTIES, poolPropertiesNode); poolNode.put(EDITOR_OUTGOING, objectMapper.createArrayNode()); ArrayNode laneShapesArrayNode = objectMapper.createArrayNode(); poolNode.put(EDITOR_CHILD_SHAPES, laneShapesArrayNode); Process process = model.getProcess(pool.getId()); if (process != null) { processFlowElements(process.findFlowElementsOfType(SequenceFlow.class), model, shapesArrayNode, poolGraphicInfo.getX(), poolGraphicInfo.getY()); for (Lane lane : process.getLanes()) { GraphicInfo laneGraphicInfo = model.getGraphicInfo(lane.getId()); ObjectNode laneNode = BpmnJsonConverterUtil.createChildShape(lane.getId(), STENCIL_LANE, laneGraphicInfo.getX() + laneGraphicInfo.getWidth(), laneGraphicInfo.getY() + laneGraphicInfo.getHeight(), laneGraphicInfo.getX(), laneGraphicInfo.getY()); laneShapesArrayNode.add(laneNode); ObjectNode lanePropertiesNode = objectMapper.createObjectNode(); lanePropertiesNode.put(PROPERTY_OVERRIDE_ID, lane.getId()); if (StringUtils.isNotEmpty(lane.getName())) { lanePropertiesNode.put(PROPERTY_NAME, lane.getName()); } laneNode.put(EDITOR_SHAPE_PROPERTIES, lanePropertiesNode); ArrayNode elementShapesArrayNode = objectMapper.createArrayNode(); laneNode.put(EDITOR_CHILD_SHAPES, elementShapesArrayNode); laneNode.put(EDITOR_OUTGOING, objectMapper.createArrayNode()); for (FlowElement flowElement : process.getFlowElements()) { if (lane.getFlowReferences().contains(flowElement.getId())) { Class<? extends BaseBpmnJsonConverter> converter = convertersToJsonMap .get(flowElement.getClass()); if (converter != null) { try { converter.newInstance().convertToJson(flowElement, this, model, elementShapesArrayNode, laneGraphicInfo.getX(), laneGraphicInfo.getY()); } catch (Exception e) { LOGGER.error("Error converting {}", flowElement, e); } } } } } } } } else { processFlowElements(model.getMainProcess().getFlowElements(), model, shapesArrayNode, 0.0, 0.0); } modelNode.put(EDITOR_CHILD_SHAPES, shapesArrayNode); return modelNode; } @Override public void processFlowElements(Collection<? extends FlowElement> flowElements, BpmnModel model, ArrayNode shapesArrayNode, double subProcessX, double subProcessY) { for (FlowElement flowElement : flowElements) { Class<? extends BaseBpmnJsonConverter> converter = convertersToJsonMap.get(flowElement.getClass()); if (converter != null) { try { converter.newInstance().convertToJson(flowElement, this, model, shapesArrayNode, subProcessX, subProcessY); } catch (Exception e) { LOGGER.error("Error converting {}", flowElement, e); } } } } public BpmnModel convertToBpmnModel(JsonNode modelNode) { BpmnModel bpmnModel = new BpmnModel(); Map<String, JsonNode> shapeMap = new HashMap<String, JsonNode>(); Map<String, JsonNode> sourceRefMap = new HashMap<String, JsonNode>(); Map<String, JsonNode> edgeMap = new HashMap<String, JsonNode>(); Map<String, List<JsonNode>> sourceAndTargetMap = new HashMap<String, List<JsonNode>>(); readShapeDI(modelNode, 0, 0, shapeMap, sourceRefMap, bpmnModel); filterAllEdges(modelNode, edgeMap, sourceAndTargetMap, shapeMap, sourceRefMap); readEdgeDI(edgeMap, sourceAndTargetMap, bpmnModel); ArrayNode shapesArrayNode = (ArrayNode) modelNode.get(EDITOR_CHILD_SHAPES); boolean emptyPoolFound = true; // first create the pool structure for (JsonNode shapeNode : shapesArrayNode) { String stencilId = BpmnJsonConverterUtil.getStencilId(shapeNode); if (STENCIL_POOL.equals(stencilId)) { Pool pool = new Pool(); pool.setId(BpmnJsonConverterUtil.getElementId(shapeNode)); pool.setName(JsonConverterUtil.getPropertyValueAsString(PROPERTY_NAME, shapeNode)); pool.setProcessRef(JsonConverterUtil.getPropertyValueAsString(PROPERTY_PROCESS_ID, shapeNode)); pool.setExecutable( JsonConverterUtil.getPropertyValueAsBoolean(PROPERTY_PROCESS_EXECUTABLE, shapeNode, true)); bpmnModel.getPools().add(pool); Process process = new Process(); process.setId(pool.getProcessRef()); process.setName(pool.getName()); process.setExecutable(pool.isExecutable()); bpmnModel.addProcess(process); processJsonElements(shapesArrayNode, modelNode, process, shapeMap); ArrayNode laneArrayNode = (ArrayNode) shapeNode.get(EDITOR_CHILD_SHAPES); for (JsonNode laneNode : laneArrayNode) { // should be a lane, but just check to be certain String laneStencilId = BpmnJsonConverterUtil.getStencilId(laneNode); if (STENCIL_LANE.equals(laneStencilId)) { emptyPoolFound = false; Lane lane = new Lane(); lane.setId(BpmnJsonConverterUtil.getElementId(laneNode)); lane.setName(JsonConverterUtil.getPropertyValueAsString(PROPERTY_NAME, laneNode)); lane.setParentProcess(process); process.getLanes().add(lane); processJsonElements(laneNode.get(EDITOR_CHILD_SHAPES), modelNode, lane, shapeMap); } } } } if (emptyPoolFound) { JsonNode processIdNode = JsonConverterUtil.getProperty(PROPERTY_PROCESS_ID, modelNode); Process process = new Process(); bpmnModel.getProcesses().add(process); if (processIdNode != null && StringUtils.isNotEmpty(processIdNode.asText())) { process.setId(processIdNode.asText()); } JsonNode processNameNode = JsonConverterUtil.getProperty(PROPERTY_NAME, modelNode); if (processNameNode != null && StringUtils.isNotEmpty(processNameNode.asText())) { process.setName(processNameNode.asText()); } JsonNode processExecutableNode = JsonConverterUtil.getProperty(PROPERTY_PROCESS_EXECUTABLE, modelNode); if (processExecutableNode != null && StringUtils.isNotEmpty(processExecutableNode.asText())) { process.setExecutable( JsonConverterUtil.getPropertyValueAsBoolean(PROPERTY_PROCESS_EXECUTABLE, modelNode)); } JsonNode processTargetNamespace = JsonConverterUtil.getProperty(PROPERTY_PROCESS_NAMESPACE, modelNode); if (processTargetNamespace != null && StringUtils.isNotEmpty(processTargetNamespace.asText())) { bpmnModel.setTargetNamespace(processTargetNamespace.asText()); } JsonNode processExecutionListenerNode = modelNode.get(EDITOR_SHAPE_PROPERTIES) .get(PROPERTY_EXECUTION_LISTENERS); if (processExecutionListenerNode != null && StringUtils.isNotEmpty(processExecutionListenerNode.asText())) { process.setExecutionListeners(convertJsonToListeners(processExecutionListenerNode)); } JsonNode processEventListenerNode = modelNode.get(EDITOR_SHAPE_PROPERTIES) .get(PROPERTY_EVENT_LISTENERS); if (processEventListenerNode != null) { process.setEventListeners(convertJsonToEventListeners(processEventListenerNode)); } processJsonElements(shapesArrayNode, modelNode, process, shapeMap); } // sequence flows are now all on root level Map<String, SubProcess> subShapesMap = new HashMap<String, SubProcess>(); for (Process process : bpmnModel.getProcesses()) { for (FlowElement flowElement : process.findFlowElementsOfType(SubProcess.class)) { SubProcess subProcess = (SubProcess) flowElement; fillSubShapes(subShapesMap, subProcess); } if (subShapesMap.size() > 0) { List<String> removeSubFlowsList = new ArrayList<String>(); List<SequenceFlow> sequenceFlowList = process.findFlowElementsOfType(SequenceFlow.class); for (FlowElement flowElement : sequenceFlowList) { SequenceFlow sequenceFlow = (SequenceFlow) flowElement; if (process.getFlowElement(flowElement.getId()) != null && subShapesMap.containsKey(sequenceFlow.getSourceRef())) { SubProcess subProcess = subShapesMap.get(sequenceFlow.getSourceRef()); subProcess.addFlowElement(sequenceFlow); removeSubFlowsList.add(sequenceFlow.getId()); } } for (String flowId : removeSubFlowsList) { process.removeFlowElement(flowId); } } } // boundary events only contain attached ref id for (Process process : bpmnModel.getProcesses()) { postProcessElements(process, process.getFlowElements()); } return bpmnModel; } @Override public void processJsonElements(JsonNode shapesArrayNode, JsonNode modelNode, BaseElement parentElement, Map<String, JsonNode> shapeMap) { for (JsonNode shapeNode : shapesArrayNode) { Class<? extends BaseBpmnJsonConverter> converter = convertersToBpmnMap .get(BpmnJsonConverterUtil.getStencilId(shapeNode)); if (converter != null) { try { converter.newInstance().convertToBpmnModel(shapeNode, modelNode, this, parentElement, shapeMap); } catch (Exception e) { LOGGER.error("Error converting {}", BpmnJsonConverterUtil.getStencilId(shapeNode), e); } } } } private List<ActivitiListener> convertJsonToListeners(JsonNode listenersNode) { List<ActivitiListener> executionListeners = new ArrayList<ActivitiListener>(); try { listenersNode = objectMapper.readTree(listenersNode.asText()); } catch (Exception e) { LOGGER.info("Listeners node can not be read", e); } JsonNode itemsArrayNode = listenersNode.get(EDITOR_PROPERTIES_GENERAL_ITEMS); if (itemsArrayNode != null) { for (JsonNode itemNode : itemsArrayNode) { JsonNode typeNode = itemNode.get(PROPERTY_EXECUTION_LISTENER_EVENT); if (typeNode != null && StringUtils.isNotEmpty(typeNode.asText())) { ActivitiListener listener = new ActivitiListener(); listener.setEvent(typeNode.asText()); if (StringUtils.isNotEmpty(itemNode.get(PROPERTY_EXECUTION_LISTENER_CLASS).asText())) { listener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_CLASS); listener.setImplementation(itemNode.get(PROPERTY_EXECUTION_LISTENER_CLASS).asText()); } else if (StringUtils .isNotEmpty(itemNode.get(PROPERTY_EXECUTION_LISTENER_EXPRESSION).asText())) { listener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_EXPRESSION); listener.setImplementation(itemNode.get(PROPERTY_EXECUTION_LISTENER_EXPRESSION).asText()); } else if (StringUtils .isNotEmpty(itemNode.get(PROPERTY_EXECUTION_LISTENER_DELEGATEEXPRESSION).asText())) { listener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); listener.setImplementation( itemNode.get(PROPERTY_EXECUTION_LISTENER_DELEGATEEXPRESSION).asText()); } // resolve the listener feild JsonNode listenerFieldsNode = null; JsonNode listenerFieldsArrayNode = null; listenerFieldsNode = itemNode.get(PROPERTY_EXECUTION_LISTENER_FIELDS); if (listenerFieldsNode != null && StringUtils.isNotEmpty(listenerFieldsNode.asText()) && !("undefined".equals(listenerFieldsNode.asText()))) { if (listenerFieldsNode.isValueNode()) { try { listenerFieldsNode = objectMapper.readTree(listenerFieldsNode.asText()); } catch (Exception e) { LOGGER.info("Listener fields node can not be read", e); } } } if (listenerFieldsNode != null) { listenerFieldsArrayNode = listenerFieldsNode.get(EDITOR_PROPERTIES_GENERAL_ITEMS); List<FieldExtension> fields = new ArrayList<FieldExtension>(); if (listenerFieldsArrayNode != null) { for (JsonNode fieldNode : listenerFieldsArrayNode) { JsonNode fieldNameNode = fieldNode.get(PROPERTY_EXECUTION_LISTENER_FIELD_NAME); if (fieldNameNode != null && StringUtils.isNotEmpty(fieldNameNode.asText())) { FieldExtension field = new FieldExtension(); field.setFieldName(fieldNameNode.asText()); field.setStringValue( getValueAsString(PROPERTY_EXECUTION_LISTENER_FIELD_VALUE, fieldNode)); field.setExpression( getValueAsString(PROPERTY_EXECUTION_LISTENER_EXPRESSION, fieldNode)); fields.add(field); } } } listener.setFieldExtensions(fields); } executionListeners.add(listener); } } } return executionListeners; } private String getValueAsString(String name, JsonNode objectNode) { String propertyValue = null; JsonNode propertyNode = objectNode.get(name); if (propertyNode != null && "null".equalsIgnoreCase(propertyNode.asText()) == false) { propertyValue = propertyNode.asText(); } return propertyValue; } private List<EventListener> convertJsonToEventListeners(JsonNode listenersNode) { List<EventListener> eventListeners = new ArrayList<EventListener>(); if (StringUtils.isEmpty(listenersNode.asText())) return eventListeners; try { listenersNode = objectMapper.readTree(listenersNode.asText()); } catch (Exception e) { LOGGER.info("Event listeners node can not be read", e); } JsonNode itemsArrayNode = listenersNode.get(EDITOR_PROPERTIES_GENERAL_ITEMS); if (itemsArrayNode != null) { for (JsonNode itemNode : itemsArrayNode) { EventListener listener = new EventListener(); if (isNotEmpty(PROPERTY_EVENT_LISTENER_EVENTS, itemNode)) { listener.setEvents(itemNode.get(PROPERTY_EVENT_LISTENER_EVENTS).asText()); } if (isNotEmpty(PROPERTY_EVENT_LISTENER_ENTITY_TYPE, itemNode)) { listener.setEntityType(itemNode.get(PROPERTY_EVENT_LISTENER_ENTITY_TYPE).asText()); } if (isNotEmpty(PROPERTY_EVENT_LISTENER_CLASS, itemNode)) { listener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_CLASS); listener.setImplementation(itemNode.get(PROPERTY_EVENT_LISTENER_CLASS).asText()); } else if (isNotEmpty(PROPERTY_EVENT_LISTENER_DELEGATEEXPRESSION, itemNode)) { listener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); listener.setImplementation(itemNode.get(PROPERTY_EVENT_LISTENER_DELEGATEEXPRESSION).asText()); } else if (isNotEmpty(PROPERTY_EVENT_LISTENER_THROW_EVENT, itemNode)) { String throwEventType = itemNode.get(PROPERTY_EVENT_LISTENER_THROW_EVENT).asText(); if (PROPERTY_EVENT_LISTENER_THROW_SIGNAL.equals(throwEventType)) { listener.setImplementation(itemNode.get(PROPERTY_EVENT_LISTENER_THROW_REFERENCE).asText()); listener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_THROW_SIGNAL_EVENT); } else if (PROPERTY_EVENT_LISTENER_THROW_GLOBAL_SIGNAL.equals(throwEventType)) { listener.setImplementation(itemNode.get(PROPERTY_EVENT_LISTENER_THROW_REFERENCE).asText()); listener.setImplementationType( ImplementationType.IMPLEMENTATION_TYPE_THROW_GLOBAL_SIGNAL_EVENT); } else if (PROPERTY_EVENT_LISTENER_THROW_MESSAGE.equals(throwEventType)) { listener.setImplementation(itemNode.get(PROPERTY_EVENT_LISTENER_THROW_REFERENCE).asText()); listener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_THROW_MESSAGE_EVENT); } else if (PROPERTY_EVENT_LISTENER_THROW_ERROR.equals(throwEventType)) { listener.setImplementation(itemNode.get(PROPERTY_EVENT_LISTENER_THROW_REFERENCE).asText()); listener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_THROW_ERROR_EVENT); } else { // Not a valid throw event type, ignore this listener definition listener = null; } } else { // No properties have been provided to have a valid implementation listener = null; } if (listener != null) { eventListeners.add(listener); } } } return eventListeners; } private boolean isNotEmpty(String propertyName, JsonNode node) { JsonNode value = node.get(propertyName); if (value != null) { return StringUtils.isNotEmpty(value.asText()); } return false; } private void fillSubShapes(Map<String, SubProcess> subShapesMap, SubProcess subProcess) { for (FlowElement flowElement : subProcess.getFlowElements()) { if (flowElement instanceof SubProcess) { SubProcess childSubProcess = (SubProcess) flowElement; fillSubShapes(subShapesMap, childSubProcess); } else { subShapesMap.put(flowElement.getId(), subProcess); } } } private void postProcessElements(FlowElementsContainer process, Collection<FlowElement> flowElementList) { for (FlowElement flowElement : flowElementList) { if (flowElement instanceof BoundaryEvent) { BoundaryEvent boundaryEvent = (BoundaryEvent) flowElement; Activity activity = retrieveAttachedRefObject(boundaryEvent.getAttachedToRefId(), process.getFlowElements()); if (activity == null) { LOGGER.warn("Boundary event " + boundaryEvent.getId() + " is not attached to any activity"); } else { boundaryEvent.setAttachedToRef(activity); activity.getBoundaryEvents().add(boundaryEvent); } } else if (flowElement instanceof SubProcess) { SubProcess subProcess = (SubProcess) flowElement; postProcessElements(subProcess, subProcess.getFlowElements()); } else if (flowElement instanceof SequenceFlow) { SequenceFlow sequenceFlow = (SequenceFlow) flowElement; FlowElement sourceFlowElement = process.getFlowElement(sequenceFlow.getSourceRef()); if (sourceFlowElement instanceof FlowNode) { ((FlowNode) sourceFlowElement).getOutgoingFlows().add(sequenceFlow); } FlowElement targerFlowElement = process.getFlowElement(sequenceFlow.getTargetRef()); if (targerFlowElement instanceof FlowNode) { ((FlowNode) targerFlowElement).getIncomingFlows().add(sequenceFlow); } } } } private Activity retrieveAttachedRefObject(String attachedToRefId, Collection<FlowElement> flowElementList) { for (FlowElement flowElement : flowElementList) { if (attachedToRefId.equals(flowElement.getId())) { return (Activity) flowElement; } else if (flowElement instanceof SubProcess) { SubProcess subProcess = (SubProcess) flowElement; Activity activity = retrieveAttachedRefObject(attachedToRefId, subProcess.getFlowElements()); if (activity != null) { return activity; } } } return null; } private void readShapeDI(JsonNode objectNode, double parentX, double parentY, Map<String, JsonNode> shapeMap, Map<String, JsonNode> sourceRefMap, BpmnModel bpmnModel) { if (objectNode.get(EDITOR_CHILD_SHAPES) != null) { for (JsonNode jsonChildNode : objectNode.get(EDITOR_CHILD_SHAPES)) { String stencilId = BpmnJsonConverterUtil.getStencilId(jsonChildNode); if (STENCIL_SEQUENCE_FLOW.equals(stencilId) == false) { GraphicInfo graphicInfo = new GraphicInfo(); JsonNode boundsNode = jsonChildNode.get(EDITOR_BOUNDS); ObjectNode upperLeftNode = (ObjectNode) boundsNode.get(EDITOR_BOUNDS_UPPER_LEFT); graphicInfo.setX(upperLeftNode.get(EDITOR_BOUNDS_X).asDouble() + parentX); graphicInfo.setY(upperLeftNode.get(EDITOR_BOUNDS_Y).asDouble() + parentY); ObjectNode lowerRightNode = (ObjectNode) boundsNode.get(EDITOR_BOUNDS_LOWER_RIGHT); graphicInfo.setWidth( lowerRightNode.get(EDITOR_BOUNDS_X).asDouble() - graphicInfo.getX() + parentX); graphicInfo.setHeight( lowerRightNode.get(EDITOR_BOUNDS_Y).asDouble() - graphicInfo.getY() + parentY); String childShapeId = jsonChildNode.get(EDITOR_SHAPE_ID).asText(); bpmnModel.addGraphicInfo(BpmnJsonConverterUtil.getElementId(jsonChildNode), graphicInfo); shapeMap.put(childShapeId, jsonChildNode); ArrayNode outgoingNode = (ArrayNode) jsonChildNode.get("outgoing"); if (outgoingNode != null && outgoingNode.size() > 0) { for (JsonNode outgoingChildNode : outgoingNode) { JsonNode resourceNode = outgoingChildNode.get(EDITOR_SHAPE_ID); if (resourceNode != null) { sourceRefMap.put(resourceNode.asText(), jsonChildNode); } } } readShapeDI(jsonChildNode, graphicInfo.getX(), graphicInfo.getY(), shapeMap, sourceRefMap, bpmnModel); } } } } private void filterAllEdges(JsonNode objectNode, Map<String, JsonNode> edgeMap, Map<String, List<JsonNode>> sourceAndTargetMap, Map<String, JsonNode> shapeMap, Map<String, JsonNode> sourceRefMap) { if (objectNode.get(EDITOR_CHILD_SHAPES) != null) { for (JsonNode jsonChildNode : objectNode.get(EDITOR_CHILD_SHAPES)) { ObjectNode childNode = (ObjectNode) jsonChildNode; String stencilId = BpmnJsonConverterUtil.getStencilId(childNode); if (STENCIL_SUB_PROCESS.equals(stencilId)) { filterAllEdges(childNode, edgeMap, sourceAndTargetMap, shapeMap, sourceRefMap); } else if (STENCIL_SEQUENCE_FLOW.equals(stencilId)) { String childEdgeId = BpmnJsonConverterUtil.getElementId(childNode); String targetRefId = childNode.get("target").get(EDITOR_SHAPE_ID).asText(); List<JsonNode> sourceAndTargetList = new ArrayList<JsonNode>(); sourceAndTargetList.add(sourceRefMap.get(childNode.get(EDITOR_SHAPE_ID).asText())); sourceAndTargetList.add(shapeMap.get(targetRefId)); edgeMap.put(childEdgeId, childNode); sourceAndTargetMap.put(childEdgeId, sourceAndTargetList); } } } } public void convertListenersToJson(List<EventListener> eventListeners, ObjectNode propertiesNode) { ObjectNode listenersNode = objectMapper.createObjectNode(); ArrayNode itemsNode = objectMapper.createArrayNode(); for (EventListener listener : eventListeners) { ObjectNode propertyItemNode = objectMapper.createObjectNode(); propertyItemNode.put(PROPERTY_EVENT_LISTENER_EVENTS, listener.getEvents()); propertyItemNode.put(PROPERTY_EVENT_LISTENER_ENTITY_TYPE, listener.getEntityType()); if (ImplementationType.IMPLEMENTATION_TYPE_CLASS.equals(listener.getImplementationType())) { propertyItemNode.put(PROPERTY_EVENT_LISTENER_CLASS, listener.getImplementation()); } else if (ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION .equals(listener.getImplementationType())) { propertyItemNode.put(PROPERTY_EVENT_LISTENER_DELEGATEEXPRESSION, listener.getImplementation()); } else if (ImplementationType.IMPLEMENTATION_TYPE_THROW_SIGNAL_EVENT .equals(listener.getImplementationType())) { propertyItemNode.put(PROPERTY_EVENT_LISTENER_THROW_EVENT, PROPERTY_EVENT_LISTENER_THROW_SIGNAL); propertyItemNode.put(PROPERTY_EVENT_LISTENER_THROW_REFERENCE, listener.getImplementation()); } else if (ImplementationType.IMPLEMENTATION_TYPE_THROW_GLOBAL_SIGNAL_EVENT .equals(listener.getImplementationType())) { propertyItemNode.put(PROPERTY_EVENT_LISTENER_THROW_EVENT, PROPERTY_EVENT_LISTENER_THROW_GLOBAL_SIGNAL); propertyItemNode.put(PROPERTY_EVENT_LISTENER_THROW_REFERENCE, listener.getImplementation()); } else if (ImplementationType.IMPLEMENTATION_TYPE_THROW_MESSAGE_EVENT .equals(listener.getImplementationType())) { propertyItemNode.put(PROPERTY_EVENT_LISTENER_THROW_EVENT, PROPERTY_EVENT_LISTENER_THROW_MESSAGE); propertyItemNode.put(PROPERTY_EVENT_LISTENER_THROW_REFERENCE, listener.getImplementation()); } else if (ImplementationType.IMPLEMENTATION_TYPE_THROW_ERROR_EVENT .equals(listener.getImplementationType())) { propertyItemNode.put(PROPERTY_EVENT_LISTENER_THROW_EVENT, PROPERTY_EVENT_LISTENER_THROW_ERROR); propertyItemNode.put(PROPERTY_EVENT_LISTENER_THROW_REFERENCE, listener.getImplementation()); } itemsNode.add(propertyItemNode); } listenersNode.put("totalCount", itemsNode.size()); listenersNode.put(EDITOR_PROPERTIES_GENERAL_ITEMS, itemsNode); propertiesNode.put(PROPERTY_EVENT_LISTENERS, listenersNode); } private void readEdgeDI(Map<String, JsonNode> edgeMap, Map<String, List<JsonNode>> sourceAndTargetMap, BpmnModel bpmnModel) { for (String edgeId : edgeMap.keySet()) { JsonNode edgeNode = edgeMap.get(edgeId); List<JsonNode> sourceAndTargetList = sourceAndTargetMap.get(edgeId); JsonNode sourceRefNode = sourceAndTargetList.get(0); JsonNode targetRefNode = sourceAndTargetList.get(1); if (sourceRefNode == null) { LOGGER.info("Skipping edge {} because source ref is null", edgeId); continue; } if (targetRefNode == null) { LOGGER.info("Skipping edge {} because target ref is null", edgeId); continue; } JsonNode dockersNode = edgeNode.get(EDITOR_DOCKERS); double sourceDockersX = dockersNode.get(0).get(EDITOR_BOUNDS_X).doubleValue(); double sourceDockersY = dockersNode.get(0).get(EDITOR_BOUNDS_Y).doubleValue(); GraphicInfo sourceInfo = bpmnModel.getGraphicInfo(BpmnJsonConverterUtil.getElementId(sourceRefNode)); GraphicInfo targetInfo = bpmnModel.getGraphicInfo(BpmnJsonConverterUtil.getElementId(targetRefNode)); /*JsonNode sourceRefBoundsNode = sourceRefNode.get(EDITOR_BOUNDS); BoundsLocation sourceRefUpperLeftLocation = getLocation(EDITOR_BOUNDS_UPPER_LEFT, sourceRefBoundsNode); BoundsLocation sourceRefLowerRightLocation = getLocation(EDITOR_BOUNDS_LOWER_RIGHT, sourceRefBoundsNode); JsonNode targetRefBoundsNode = targetRefNode.get(EDITOR_BOUNDS); BoundsLocation targetRefUpperLeftLocation = getLocation(EDITOR_BOUNDS_UPPER_LEFT, targetRefBoundsNode); BoundsLocation targetRefLowerRightLocation = getLocation(EDITOR_BOUNDS_LOWER_RIGHT, targetRefBoundsNode);*/ double sourceRefLineX = sourceInfo.getX() + sourceDockersX; double sourceRefLineY = sourceInfo.getY() + sourceDockersY; double nextPointInLineX; double nextPointInLineY; nextPointInLineX = dockersNode.get(1).get(EDITOR_BOUNDS_X).doubleValue(); nextPointInLineY = dockersNode.get(1).get(EDITOR_BOUNDS_Y).doubleValue(); if (dockersNode.size() == 2) { nextPointInLineX += targetInfo.getX(); nextPointInLineY += targetInfo.getY(); } Line2D firstLine = new Line2D(sourceRefLineX, sourceRefLineY, nextPointInLineX, nextPointInLineY); String sourceRefStencilId = BpmnJsonConverterUtil.getStencilId(sourceRefNode); String targetRefStencilId = BpmnJsonConverterUtil.getStencilId(targetRefNode); List<GraphicInfo> graphicInfoList = new ArrayList<GraphicInfo>(); if (DI_CIRCLES.contains(sourceRefStencilId)) { Circle2D eventCircle = new Circle2D(sourceInfo.getX() + sourceDockersX, sourceInfo.getY() + sourceDockersY, sourceDockersX); Collection<Point2D> intersections = eventCircle.intersections(firstLine); Point2D intersection = intersections.iterator().next(); graphicInfoList.add(createGraphicInfo(intersection.getX(), intersection.getY())); } else if (DI_RECTANGLES.contains(sourceRefStencilId)) { Polyline2D rectangle = createRectangle(sourceInfo); Collection<Point2D> intersections = rectangle.intersections(firstLine); Point2D intersection = intersections.iterator().next(); graphicInfoList.add(createGraphicInfo(intersection.getX(), intersection.getY())); } else if (DI_GATEWAY.contains(sourceRefStencilId)) { Polyline2D gatewayRectangle = createGateway(sourceInfo); Collection<Point2D> intersections = gatewayRectangle.intersections(firstLine); Point2D intersection = intersections.iterator().next(); graphicInfoList.add(createGraphicInfo(intersection.getX(), intersection.getY())); } Line2D lastLine = null; if (dockersNode.size() > 2) { for (int i = 1; i < dockersNode.size() - 1; i++) { double x = dockersNode.get(i).get(EDITOR_BOUNDS_X).doubleValue(); double y = dockersNode.get(i).get(EDITOR_BOUNDS_Y).doubleValue(); graphicInfoList.add(createGraphicInfo(x, y)); } double startLastLineX = dockersNode.get(dockersNode.size() - 2).get(EDITOR_BOUNDS_X).doubleValue(); double startLastLineY = dockersNode.get(dockersNode.size() - 2).get(EDITOR_BOUNDS_Y).doubleValue(); double endLastLineX = dockersNode.get(dockersNode.size() - 1).get(EDITOR_BOUNDS_X).doubleValue(); double endLastLineY = dockersNode.get(dockersNode.size() - 1).get(EDITOR_BOUNDS_Y).doubleValue(); endLastLineX += targetInfo.getX(); endLastLineY += targetInfo.getY(); lastLine = new Line2D(startLastLineX, startLastLineY, endLastLineX, endLastLineY); } else { lastLine = firstLine; } if (DI_RECTANGLES.contains(targetRefStencilId)) { Polyline2D rectangle = createRectangle(targetInfo); Collection<Point2D> intersections = rectangle.intersections(lastLine); Point2D intersection = intersections.iterator().next(); graphicInfoList.add(createGraphicInfo(intersection.getX(), intersection.getY())); } else if (DI_CIRCLES.contains(targetRefStencilId)) { double targetDockersX = dockersNode.get(dockersNode.size() - 1).get(EDITOR_BOUNDS_X).doubleValue(); double targetDockersY = dockersNode.get(dockersNode.size() - 1).get(EDITOR_BOUNDS_Y).doubleValue(); Circle2D eventCircle = new Circle2D(targetInfo.getX() + targetDockersX, targetInfo.getY() + targetDockersY, targetDockersX); Collection<Point2D> intersections = eventCircle.intersections(lastLine); Point2D intersection = intersections.iterator().next(); graphicInfoList.add(createGraphicInfo(intersection.getX(), intersection.getY())); } else if (DI_GATEWAY.contains(targetRefStencilId)) { Polyline2D gatewayRectangle = createGateway(targetInfo); Collection<Point2D> intersections = gatewayRectangle.intersections(lastLine); Point2D intersection = intersections.iterator().next(); graphicInfoList.add(createGraphicInfo(intersection.getX(), intersection.getY())); } bpmnModel.addFlowGraphicInfoList(edgeId, graphicInfoList); } } private Polyline2D createRectangle(GraphicInfo graphicInfo) { Polyline2D rectangle = new Polyline2D(new Point2D(graphicInfo.getX(), graphicInfo.getY()), new Point2D(graphicInfo.getX() + graphicInfo.getWidth(), graphicInfo.getY()), new Point2D(graphicInfo.getX() + graphicInfo.getWidth(), graphicInfo.getY() + graphicInfo.getHeight()), new Point2D(graphicInfo.getX(), graphicInfo.getY() + graphicInfo.getHeight()), new Point2D(graphicInfo.getX(), graphicInfo.getY())); return rectangle; } private Polyline2D createGateway(GraphicInfo graphicInfo) { double middleX = graphicInfo.getX() + (graphicInfo.getWidth() / 2); double middleY = graphicInfo.getY() + (graphicInfo.getHeight() / 2); Polyline2D gatewayRectangle = new Polyline2D(new Point2D(graphicInfo.getX(), middleY), new Point2D(middleX, graphicInfo.getY()), new Point2D(graphicInfo.getX() + graphicInfo.getWidth(), middleY), new Point2D(middleX, graphicInfo.getY() + graphicInfo.getHeight()), new Point2D(graphicInfo.getX(), middleY)); return gatewayRectangle; } private GraphicInfo createGraphicInfo(double x, double y) { GraphicInfo graphicInfo = new GraphicInfo(); graphicInfo.setX(x); graphicInfo.setY(y); return graphicInfo; } }