/* 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.text.SimpleDateFormat;
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.BooleanDataObject;
import org.activiti.bpmn.model.BoundaryEvent;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.DateDataObject;
import org.activiti.bpmn.model.DoubleDataObject;
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.IntegerDataObject;
import org.activiti.bpmn.model.ItemDefinition;
import org.activiti.bpmn.model.Lane;
import org.activiti.bpmn.model.LongDataObject;
import org.activiti.bpmn.model.Pool;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.StringDataObject;
import org.activiti.bpmn.model.SubProcess;
import org.activiti.bpmn.model.ValuedDataObject;
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>>();
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
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());
}
if (!mainProcess.getDataObjects().isEmpty()) {
convertDataPropertiesToJson(mainProcess.getDataObjects(), propertiesNode);
}
modelNode.put(EDITOR_SHAPE_PROPERTIES, propertiesNode);
if (!model.getPools().isEmpty()) {
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));
}
JsonNode processDataPropertiesNode = modelNode.get(EDITOR_SHAPE_PROPERTIES).get(PROPERTY_DATA_PROPERTIES);
if (processDataPropertiesNode != null) {
List<ValuedDataObject> dataObjects = convertJsonToDataProperties(processDataPropertiesNode, process);
process.setDataObjects(dataObjects);
process.getFlowElements().addAll(dataObjects);
}
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.isEmpty()) {
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;
}
protected List<ValuedDataObject> convertJsonToDataProperties(JsonNode objectNode, BaseElement element) {
List<ValuedDataObject> dataObjects = new ArrayList<ValuedDataObject>();
if (objectNode != null) {
if (objectNode.isValueNode() && StringUtils.isNotEmpty(objectNode.asText())) {
try {
objectNode = objectMapper.readTree(objectNode.asText());
} catch (Exception e) {
LOGGER.info("Data properties node cannot be read", e);
}
}
JsonNode itemsArrayNode = objectNode.get(EDITOR_PROPERTIES_GENERAL_ITEMS);
if (itemsArrayNode != null) {
for (JsonNode dataNode : itemsArrayNode) {
JsonNode dataIdNode = dataNode.get(PROPERTY_DATA_ID);
if (dataIdNode != null && StringUtils.isNotEmpty(dataIdNode.asText())) {
ValuedDataObject dataObject = null;
ItemDefinition itemSubjectRef = new ItemDefinition();
String dataType = dataNode.get(PROPERTY_DATA_TYPE).asText();
if (dataType.equals("string")) {
dataObject = new StringDataObject();
} else if (dataType.equals("int")) {
dataObject = new IntegerDataObject();
} else if (dataType.equals("long")) {
dataObject = new LongDataObject();
} else if (dataType.equals("double")) {
dataObject = new DoubleDataObject();
} else if (dataType.equals("boolean")) {
dataObject = new BooleanDataObject();
} else if (dataType.equals("datetime")) {
dataObject = new DateDataObject();
} else {
LOGGER.error("Error converting {}", dataIdNode.asText());
}
if (null != dataObject) {
dataObject.setId(dataIdNode.asText());
dataObject.setName(dataNode.get(PROPERTY_DATA_NAME).asText());
itemSubjectRef.setStructureRef("xsd:" + dataType);
dataObject.setItemSubjectRef(itemSubjectRef);
if (dataObject instanceof DateDataObject) {
try {
dataObject.setValue(sdf.parse(dataNode.get(PROPERTY_DATA_VALUE).asText()));
} catch (Exception e) {
LOGGER.error("Error converting {}", dataObject.getName(), e);
}
} else {
dataObject.setValue(dataNode.get(PROPERTY_DATA_VALUE).asText());
}
dataObjects.add(dataObject);
}
}
}
}
}
return dataObjects;
}
protected void convertDataPropertiesToJson(List<ValuedDataObject> dataObjects, ObjectNode propertiesNode) {
ObjectNode dataPropertiesNode = objectMapper.createObjectNode();
ArrayNode itemsNode = objectMapper.createArrayNode();
for (ValuedDataObject dObj : dataObjects) {
ObjectNode propertyItemNode = objectMapper.createObjectNode();
propertyItemNode.put(PROPERTY_DATA_ID, dObj.getId());
propertyItemNode.put(PROPERTY_DATA_NAME, dObj.getName());
String itemSubjectRefQName = dObj.getItemSubjectRef().getStructureRef();
// remove namespace prefix
String dataType = itemSubjectRefQName.substring(itemSubjectRefQName.indexOf(':') + 1);
propertyItemNode.put(PROPERTY_DATA_TYPE, dataType);
Object dObjValue = dObj.getValue();
String value = new String();
if (null == dObjValue)
{
propertyItemNode.put(PROPERTY_DATA_VALUE, "");
}
else
{
if ("datetime". equals(dataType)) {
value = sdf.format(dObjValue);
} else {
value = new String(dObjValue.toString());
}
propertyItemNode.put(PROPERTY_DATA_VALUE, value.toString());
}
itemsNode.add(propertyItemNode);
}
dataPropertiesNode.put("totalCount", itemsNode.size());
dataPropertiesNode.put(EDITOR_PROPERTIES_GENERAL_ITEMS, itemsNode);
propertiesNode.put("dataproperties", dataPropertiesNode);
}
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;
}
}