org.activiti.designer.eclipse.bpmnimport.BpmnFileReader.java Source code

Java tutorial

Introduction

Here is the source code for org.activiti.designer.eclipse.bpmnimport.BpmnFileReader.java

Source

/* 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.designer.eclipse.bpmnimport;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;

import org.activiti.designer.eclipse.bpmn.BpmnParser;
import org.activiti.designer.eclipse.bpmn.GraphicInfo;
import org.activiti.designer.eclipse.bpmn.SequenceFlowModel;
import org.activiti.designer.eclipse.preferences.PreferencesUtil;
import org.activiti.designer.util.preferences.Preferences;
import org.apache.commons.lang.StringUtils;
import org.eclipse.bpmn2.Activity;
import org.eclipse.bpmn2.BoundaryEvent;
import org.eclipse.bpmn2.Bpmn2Factory;
import org.eclipse.bpmn2.BusinessRuleTask;
import org.eclipse.bpmn2.CallActivity;
import org.eclipse.bpmn2.CandidateGroup;
import org.eclipse.bpmn2.CandidateUser;
import org.eclipse.bpmn2.Documentation;
import org.eclipse.bpmn2.EndEvent;
import org.eclipse.bpmn2.ErrorEventDefinition;
import org.eclipse.bpmn2.Event;
import org.eclipse.bpmn2.EventDefinition;
import org.eclipse.bpmn2.ExclusiveGateway;
import org.eclipse.bpmn2.FieldExtension;
import org.eclipse.bpmn2.FlowElement;
import org.eclipse.bpmn2.FlowNode;
import org.eclipse.bpmn2.Gateway;
import org.eclipse.bpmn2.InclusiveGateway;
import org.eclipse.bpmn2.MailTask;
import org.eclipse.bpmn2.ManualTask;
import org.eclipse.bpmn2.ParallelGateway;
import org.eclipse.bpmn2.ReceiveTask;
import org.eclipse.bpmn2.ScriptTask;
import org.eclipse.bpmn2.SequenceFlow;
import org.eclipse.bpmn2.ServiceTask;
import org.eclipse.bpmn2.StartEvent;
import org.eclipse.bpmn2.SubProcess;
import org.eclipse.bpmn2.Task;
import org.eclipse.bpmn2.UserTask;
import org.eclipse.emf.common.util.EList;
import org.eclipse.graphiti.features.IAddFeature;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.context.impl.AddConnectionContext;
import org.eclipse.graphiti.features.context.impl.AddContext;
import org.eclipse.graphiti.mm.pictograms.Anchor;
import org.eclipse.graphiti.mm.pictograms.ChopboxAnchor;
import org.eclipse.graphiti.mm.pictograms.ContainerShape;
import org.eclipse.graphiti.mm.pictograms.Diagram;
import org.eclipse.graphiti.mm.pictograms.PictogramElement;
import org.eclipse.graphiti.mm.pictograms.Shape;
import org.eclipse.graphiti.services.Graphiti;
import org.eclipse.graphiti.services.ILinkService;

/**
 * @author Tijs Rademakers
 */
public class BpmnFileReader {

    private static final int START_X = 30;
    private static final int START_Y = 200;
    private static final int EVENT_WIDTH = 35;
    private static final int EVENT_HEIGHT = 35;
    private static final int TASK_WIDTH = 105;
    private static final int TASK_HEIGHT = 55;
    private static final int GATEWAY_WIDTH = 40;
    private static final int GATEWAY_HEIGHT = 40;
    private static final int SEQUENCEFLOW_WIDTH = 40;

    private Diagram diagram;
    private IFeatureProvider featureProvider;
    private String filename;
    private InputStream fileStream;
    private String processName;

    private BpmnParser bpmnParser = new BpmnParser();
    private Map<String, GraphicInfo> yMap = new HashMap<String, GraphicInfo>();
    private List<SubProcess> subProcessList = new ArrayList<SubProcess>();

    private boolean useBPMNDI = false;

    public BpmnFileReader(String filename, Diagram diagram, IFeatureProvider featureProvider) {
        this.filename = filename;
        this.diagram = diagram;
        this.featureProvider = featureProvider;
    }

    public BpmnFileReader(InputStream fileStream, String processName, Diagram diagram,
            IFeatureProvider featureProvider) {
        this.fileStream = fileStream;
        this.processName = processName;
        this.diagram = diagram;
        this.featureProvider = featureProvider;
    }

    public void openStream() {
        File bpmnFile = new File(filename);
        if (bpmnFile.exists() == false) {
            System.out.println("bpmn file does not exist " + filename);
            return;
        }
        processName = filename.substring(filename.lastIndexOf(File.separator) + 1);
        processName = processName.substring(0, processName.indexOf("."));
        try {
            fileStream = new FileInputStream(bpmnFile);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void readBpmn() {
        try {
            XMLInputFactory xif = XMLInputFactory.newInstance();
            InputStreamReader in = new InputStreamReader(fileStream, "UTF-8");
            XMLStreamReader xtr = xif.createXMLStreamReader(in);
            bpmnParser.parseBpmn(xtr);

            if (bpmnParser.bpmnList.size() == 0)
                return;

            org.eclipse.bpmn2.Process process = Bpmn2Factory.eINSTANCE.createProcess();
            String processId = processName.replace(" ", "");
            process.setId(processId);
            if (bpmnParser.process != null && StringUtils.isNotEmpty(bpmnParser.process.getName())) {
                process.setName(bpmnParser.process.getName());
            } else {
                process.setName(processName);
            }
            if (bpmnParser.process != null && StringUtils.isNotEmpty(bpmnParser.process.getNamespace())) {
                process.setNamespace(bpmnParser.process.getNamespace());
            }

            Documentation documentation = null;
            if (bpmnParser.process == null || bpmnParser.process.getDocumentation().size() == 0) {
                documentation = Bpmn2Factory.eINSTANCE.createDocumentation();
                documentation.setId("documentation_process");
                documentation.setText("");
            } else {
                documentation = bpmnParser.process.getDocumentation().get(0);
            }

            process.getDocumentation().add(documentation);

            if (bpmnParser.process != null && bpmnParser.process.getExecutionListeners().size() > 0) {
                process.getExecutionListeners().addAll(bpmnParser.process.getExecutionListeners());
            }
            diagram.eResource().getContents().add(process);

            if (PreferencesUtil.getBooleanPreference(Preferences.IMPORT_USE_BPMNDI)
                    && bpmnParser.bpmdiInfoFound == true) {
                useBPMNDI = true;
                drawDiagramWithBPMNDI(diagram, featureProvider, bpmnParser.bpmnList, bpmnParser.sequenceFlowList,
                        bpmnParser.locationMap);
            } else {

                List<FlowElement> wrongOrderList = createDiagramElements(bpmnParser.bpmnList);
                if (wrongOrderList.size() > 0) {

                    int counter = 0;
                    while (wrongOrderList.size() > 0 && counter < 10) {
                        int sizeBefore = wrongOrderList.size();
                        wrongOrderList = createDiagramElements(wrongOrderList);

                        if (sizeBefore <= wrongOrderList.size()) {
                            counter++;
                        } else {
                            counter = 0;
                        }
                    }
                }
                drawSequenceFlows();
            }
            setFriendlyIds();
            xtr.close();
            in.close();
            fileStream.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private List<FlowElement> createDiagramElements(List<FlowElement> flowList) {
        SubProcess activeSubProcess = null;
        List<FlowElement> wrongOrderList = new ArrayList<FlowElement>();
        Set<BoundaryEvent> boundaryEventList = new HashSet<BoundaryEvent>();

        // look for boundary events
        for (FlowElement flowElement : flowList) {
            if (flowElement instanceof BoundaryEvent) {
                boundaryEventList.add((BoundaryEvent) flowElement);
            }
        }

        // first look for start event
        for (FlowElement startElement : flowList) {

            if (startElement instanceof StartEvent) {
                if (activeSubProcess == null || containsFlowElementId(activeSubProcess.getFlowElements(),
                        startElement.getId()) == false) {
                    GraphicInfo graphicInfo = getNextGraphicInfo(null, startElement, yMap, boundaryEventList);
                    yMap.put(startElement.getId(), graphicInfo);
                    addBpmnElementToDiagram(startElement, graphicInfo, diagram);

                    processDiagramInSequence(startElement, flowList, activeSubProcess, wrongOrderList,
                            boundaryEventList);

                    break;

                }
            }
        }
        return wrongOrderList;
    }

    private void processDiagramInSequence(FlowElement previousElement, List<FlowElement> flowList,
            SubProcess activeSubProcess, List<FlowElement> wrongOrderList, Set<BoundaryEvent> boundaryEventList) {

        for (SequenceFlowModel sequence : bpmnParser.sequenceFlowList) {
            if (sequence.sourceRef != null && sequence.sourceRef.equals(previousElement.getId())
                    && sequence.targetRef != null && yMap.containsKey(sequence.targetRef) == false) {

                for (FlowElement flowElement : flowList) {
                    if (sequence.targetRef.equals(flowElement.getId())) {

                        if (multipleIncomingSequenceFlows(flowElement, bpmnParser.sequenceFlowList) > 1) {
                            try {
                                getMaxX(flowElement.getId());
                                calculateDivergingElementY(flowElement, bpmnParser.sequenceFlowList);

                            } catch (FlowSourceNotFoundException e) {
                                if (activeSubProcess == null
                                        || containsFlowElementId(activeSubProcess.getFlowElements(),
                                                flowElement.getId()) == false) {
                                    wrongOrderList.add(flowElement);
                                }
                                continue;
                            }
                        }

                        GraphicInfo graphicInfo = getNextGraphicInfo(previousElement, flowElement, yMap,
                                boundaryEventList);

                        yMap.put(flowElement.getId(), graphicInfo);

                        if (flowElement instanceof SubProcess) {
                            activeSubProcess = (SubProcess) flowElement;
                            subProcessList.add(activeSubProcess);

                        } else if (activeSubProcess == null
                                || containsFlowElementId(activeSubProcess.getFlowElements(),
                                        flowElement.getId()) == false) {

                            addBpmnElementToDiagram(flowElement, graphicInfo, diagram);
                        }

                        processDiagramInSequence(flowElement, flowList, activeSubProcess, wrongOrderList,
                                boundaryEventList);

                        if (boundaryEventList.size() > 0 && (flowElement instanceof SubProcess
                                || flowElement instanceof CallActivity || flowElement instanceof Task)) {

                            if (flowElement instanceof SubProcess || activeSubProcess == null
                                    || containsFlowElementId(activeSubProcess.getFlowElements(),
                                            flowElement.getId()) == false) {

                                for (BoundaryEvent boundaryEvent : boundaryEventList) {
                                    if (boundaryEvent.getAttachedToRef() != null && boundaryEvent.getAttachedToRef()
                                            .getId().equals(flowElement.getId())) {

                                        GraphicInfo boundaryGraphicInfo = getNextGraphicInfo(null, boundaryEvent,
                                                yMap, boundaryEventList);
                                        yMap.put(boundaryEvent.getId(), boundaryGraphicInfo);
                                        addBpmnElementToDiagram(boundaryEvent, boundaryGraphicInfo, diagram);

                                        processDiagramInSequence(boundaryEvent, flowList, activeSubProcess,
                                                wrongOrderList, boundaryEventList);
                                    }
                                }
                            }
                        }

                        break;
                    }
                }
            }
        }
    }

    private boolean containsFlowElementId(List<FlowElement> flowElementList, String id) {
        for (FlowElement flowElement : flowElementList) {
            if (id.equals(flowElement.getId())) {
                return true;
            }
        }
        return false;
    }

    private GraphicInfo getNextGraphicInfo(FlowElement sourceFlowElement, FlowElement newFlowElement,
            Map<String, GraphicInfo> yMap, Set<BoundaryEvent> boundaryEventList) {

        GraphicInfo graphicInfo = new GraphicInfo();
        GraphicInfo sourceInfo = null;
        if (sourceFlowElement != null && yMap.containsKey(sourceFlowElement.getId())) {
            sourceInfo = yMap.get(sourceFlowElement.getId());
            if (sourceFlowElement instanceof BoundaryEvent && newFlowElement instanceof Task) {
                sourceInfo.x -= 38;
            }
        }

        int x = 0;
        int y = 0;
        if (sourceInfo != null) {
            x = sourceInfo.x;
            y = sourceInfo.y;

            if (sourceFlowElement instanceof BoundaryEvent) {
                y += SEQUENCEFLOW_WIDTH + TASK_HEIGHT;

            } else {

                if (multipleOutgoingSequenceFlows(sourceFlowElement, bpmnParser.sequenceFlowList) > 1) {
                    if (sourceFlowElement instanceof Gateway) {
                        x += GATEWAY_WIDTH;
                    } else if (sourceFlowElement instanceof Task) {
                        x += TASK_WIDTH;
                    } else if (sourceFlowElement instanceof Event) {
                        x += EVENT_WIDTH;
                    } else {
                        x += TASK_WIDTH;
                    }
                    y = calculateDirectElementChildY(sourceFlowElement, newFlowElement.getId(), sourceInfo.y,
                            bpmnParser.sequenceFlowList);

                } else if (sourceFlowElement instanceof Gateway) {
                    x += GATEWAY_WIDTH;
                    if (newFlowElement instanceof Task) {
                        y -= 7;
                    } else if (newFlowElement instanceof EndEvent) {
                        y += 3;
                    }

                } else if (sourceFlowElement instanceof Event) {
                    x += EVENT_WIDTH;
                    if (newFlowElement instanceof Task) {
                        y -= 10;
                    }

                } else if (sourceFlowElement instanceof SubProcess) {
                    x += sourceInfo.width;
                    int height = 0;
                    if (newFlowElement instanceof Task) {
                        height = TASK_HEIGHT;
                    } else if (newFlowElement instanceof Gateway) {
                        height = GATEWAY_HEIGHT;
                    } else if (newFlowElement instanceof Event) {
                        height = EVENT_HEIGHT;
                    }
                    y += ((sourceInfo.height / 2) - (height / 2));
                } else {
                    x += TASK_WIDTH;
                }
                x += SEQUENCEFLOW_WIDTH;

                if (newFlowElement instanceof EndEvent && sourceFlowElement instanceof Task) {
                    y += 10;
                }

                if (multipleIncomingSequenceFlows(newFlowElement, bpmnParser.sequenceFlowList) > 1) {

                    y = calculateDivergingElementY(newFlowElement, bpmnParser.sequenceFlowList);
                    x = getMaxX(newFlowElement.getId());

                } else if (newFlowElement instanceof Gateway) {
                    if (sourceFlowElement instanceof Task) {
                        y += 7;
                    } else if (sourceFlowElement instanceof StartEvent) {
                        y -= 2;
                    }
                }
            }

        } else {
            x = START_X;
            y = START_Y;
        }

        graphicInfo.x = x;
        graphicInfo.y = y;

        if (newFlowElement instanceof Event) {
            graphicInfo.height = EVENT_HEIGHT;
            if (newFlowElement instanceof BoundaryEvent) {
                BoundaryEvent boundaryEvent = (BoundaryEvent) newFlowElement;
                if (boundaryEvent.getAttachedToRef() instanceof SubProcess
                        && yMap.containsKey(boundaryEvent.getAttachedToRef().getId())) {
                    GraphicInfo attachGraphInfo = yMap.get(boundaryEvent.getAttachedToRef().getId());
                    graphicInfo.x = attachGraphInfo.x + attachGraphInfo.width / 2;
                    graphicInfo.y = attachGraphInfo.y + attachGraphInfo.height - 15;
                } else if (yMap.containsKey(boundaryEvent.getAttachedToRef().getId())) {
                    GraphicInfo attachGraphInfo = yMap.get(boundaryEvent.getAttachedToRef().getId());
                    graphicInfo.x = attachGraphInfo.x + TASK_WIDTH - 25;
                    graphicInfo.y = attachGraphInfo.y + TASK_HEIGHT - 25;
                }
            }
        } else if (newFlowElement instanceof Gateway) {
            graphicInfo.height = GATEWAY_HEIGHT;
        } else if (newFlowElement instanceof SubProcess) {
            int width = 0;
            int height = 0;
            Map<String, GraphicInfo> subYMap = new HashMap<String, GraphicInfo>();
            List<FlowElement> subFlowElementList = new ArrayList<FlowElement>();

            // first go for start event
            for (FlowElement startElement : ((SubProcess) newFlowElement).getFlowElements()) {
                if (startElement instanceof StartEvent) {
                    GraphicInfo subGraphicInfo = new GraphicInfo();
                    subGraphicInfo.height = EVENT_HEIGHT;
                    subGraphicInfo.x = 20;
                    subGraphicInfo.y = 50;
                    subYMap.put(startElement.getId(), subGraphicInfo);
                    subFlowElementList.add(startElement);
                    if (subGraphicInfo.x > width)
                        width = subGraphicInfo.x;
                    if (subGraphicInfo.y > height)
                        height = subGraphicInfo.y;

                    processSubDiagramInSequence(startElement, (SubProcess) newFlowElement, subFlowElementList,
                            subYMap, boundaryEventList);

                    break;
                }
            }

            for (String subElementId : subYMap.keySet()) {
                GraphicInfo subGraphicInfo = subYMap.get(subElementId);
                if (subGraphicInfo.x > width)
                    width = subGraphicInfo.x;
                if (subGraphicInfo.y > height)
                    height = subGraphicInfo.y;
            }

            graphicInfo.width = width + 80;
            graphicInfo.height = height + 40 + TASK_HEIGHT;

            if (yMap.containsKey(sourceFlowElement.getId())) {
                GraphicInfo subSourceInfo = yMap.get(sourceFlowElement.getId());
                graphicInfo.y = subSourceInfo.y + (subSourceInfo.height / 2) - (graphicInfo.height / 2);
            }

            addBpmnElementToDiagram(newFlowElement, graphicInfo, diagram);

            int differenceInitialStartEventAndSubProcessHeight = (graphicInfo.height / 2) - 50 - (EVENT_HEIGHT / 2);

            ILinkService linkService = Graphiti.getLinkService();
            List<PictogramElement> pictoList = linkService.getPictogramElements(diagram,
                    (SubProcess) newFlowElement);
            if (pictoList != null && pictoList.size() > 0) {
                ContainerShape parent = (ContainerShape) pictoList.get(0);
                for (FlowElement subFlowElement : subFlowElementList) {
                    GraphicInfo subInfoElem = subYMap.get(subFlowElement.getId());
                    subInfoElem.y += differenceInitialStartEventAndSubProcessHeight;
                    addBpmnElementToDiagram(subFlowElement, subYMap.get(subFlowElement.getId()), parent);
                }
            }

        } else {
            graphicInfo.height = TASK_HEIGHT;
        }

        graphicInfo.element = newFlowElement;
        return graphicInfo;
    }

    private void processSubDiagramInSequence(FlowElement previousElement, SubProcess subProcess,
            List<FlowElement> subFlowElementList, Map<String, GraphicInfo> subYMap,
            Set<BoundaryEvent> boundaryEventList) {

        for (SequenceFlowModel sequence : bpmnParser.sequenceFlowList) {
            if (sequence.sourceRef != null && sequence.sourceRef.equals(previousElement.getId())
                    && sequence.targetRef != null && subYMap.containsKey(sequence.targetRef) == false) {

                for (FlowElement subFlowElement : subProcess.getFlowElements()) {
                    if (sequence.targetRef.equals(subFlowElement.getId())) {
                        FlowElement subSourceElement = sourceRef(subFlowElement.getId(), subYMap);
                        GraphicInfo subGraphicInfo = getNextGraphicInfo(subSourceElement, subFlowElement, subYMap,
                                boundaryEventList);
                        if (subGraphicInfo.y < 0) {
                            subGraphicInfo.y = 0;
                        }

                        subYMap.put(subFlowElement.getId(), subGraphicInfo);
                        subFlowElementList.add(subFlowElement);

                        processSubDiagramInSequence(subFlowElement, subProcess, subFlowElementList, subYMap,
                                boundaryEventList);

                        if (boundaryEventList.size() > 0
                                && (subFlowElement instanceof CallActivity || subFlowElement instanceof Task)) {

                            for (BoundaryEvent boundaryEvent : boundaryEventList) {
                                if (boundaryEvent.getAttachedToRef() != null && boundaryEvent.getAttachedToRef()
                                        .getId().equals(subFlowElement.getId())) {

                                    GraphicInfo boundaryGraphicInfo = getNextGraphicInfo(null, boundaryEvent,
                                            subYMap, boundaryEventList);
                                    subYMap.put(boundaryEvent.getId(), boundaryGraphicInfo);
                                    subFlowElementList.add(boundaryEvent);

                                    processSubDiagramInSequence(boundaryEvent, subProcess, subFlowElementList,
                                            subYMap, boundaryEventList);
                                }
                            }
                        }

                        break;
                    }
                }
            }
        }
    }

    private FlowElement sourceRef(String id, Map<String, GraphicInfo> graphInfoMap) {
        FlowElement sourceRef = null;
        String sourceRefString = null;
        for (SequenceFlowModel sequenceFlowModel : bpmnParser.sequenceFlowList) {
            if (sequenceFlowModel.targetRef.equals(id) && graphInfoMap.containsKey(sequenceFlowModel.sourceRef)) {
                sourceRefString = sequenceFlowModel.sourceRef;
            }
        }
        if (sourceRefString != null) {
            for (FlowElement flowElement : bpmnParser.bpmnList) {
                if (flowElement.getId().equals(sourceRefString)) {
                    sourceRef = flowElement;
                }
            }
        }
        return sourceRef;
    }

    private int getMaxX(String id) {
        int maxX = 0;
        String sourceRef = null;
        for (SequenceFlowModel sequenceFlowModel : bpmnParser.sequenceFlowList) {
            if (sequenceFlowModel.targetRef.equals(id)) {
                if (yMap.containsKey(sequenceFlowModel.sourceRef)) {
                    int sourceX = yMap.get(sequenceFlowModel.sourceRef).x;
                    if (sourceX > maxX) {
                        maxX = sourceX;
                        sourceRef = sequenceFlowModel.sourceRef;
                    }
                } else {
                    throw new FlowSourceNotFoundException();
                }
            }
        }
        if (sourceRef != null) {
            for (FlowElement flowElement : bpmnParser.bpmnList) {
                if (flowElement.getId().equals(sourceRef)) {
                    if (flowElement instanceof Event) {
                        maxX += EVENT_WIDTH;
                    } else if (flowElement instanceof Gateway) {
                        maxX += GATEWAY_WIDTH;
                    } else if (flowElement instanceof Task) {
                        maxX += TASK_WIDTH;
                    }
                }
            }
        }
        maxX += SEQUENCEFLOW_WIDTH;
        return maxX;
    }

    private int multipleOutgoingSequenceFlows(FlowElement element, List<SequenceFlowModel> sequenceFlowList) {
        int counter = 0;
        for (SequenceFlowModel sequenceFlowModel : sequenceFlowList) {
            if (sequenceFlowModel.sourceRef.equals(element.getId())) {
                counter++;
            }
        }
        return counter;
    }

    private int multipleIncomingSequenceFlows(FlowElement element, List<SequenceFlowModel> sequenceFlowList) {
        int counter = 0;
        for (SequenceFlowModel sequenceFlowModel : sequenceFlowList) {
            if (sequenceFlowModel.targetRef.equals(element.getId())) {
                String source = sequenceFlowModel.sourceRef;
                int sourceCounter = 0;
                for (SequenceFlowModel sourceFlowModel : sequenceFlowList) {
                    if (sourceFlowModel.sourceRef.equals(source)) {
                        for (FlowElement flowElement : bpmnParser.bpmnList) {
                            if (flowElement.getId().equals(source)
                                    && flowElement instanceof BoundaryEvent == false) {
                                sourceCounter++;
                            }
                        }
                    }
                }
                if (sourceCounter == 1) {
                    counter++;
                }
            }
        }
        return counter;
    }

    private int calculateDivergingElementY(FlowElement element, List<SequenceFlowModel> sequenceFlowList) {

        if (element instanceof Gateway) {
            GraphicInfo previousGateway = getDivergingGateway(element, sequenceFlowList,
                    element.getClass().getName());
            if (previousGateway != null) {
                return previousGateway.y;
            }
        }

        int y = 0;
        List<SequenceFlowModel> flowList = new ArrayList<SequenceFlowModel>();
        for (SequenceFlowModel sequenceFlowModel : sequenceFlowList) {
            if (sequenceFlowModel.targetRef.equals(element.getId())) {
                flowList.add(sequenceFlowModel);
            }
        }

        if (flowList.size() % 2 == 0) {
            int middleTop = (flowList.size() / 2) - 1;
            int middleBottom = flowList.size() / 2;

            if (yMap.containsKey(flowList.get(middleTop).sourceRef)
                    && yMap.containsKey(flowList.get(middleBottom).sourceRef)) {

                GraphicInfo middleTopInfo = yMap.get(flowList.get(middleTop).sourceRef);
                GraphicInfo middleBottomInfo = yMap.get(flowList.get(middleBottom).sourceRef);
                y = middleTopInfo.y + middleTopInfo.height;
                int middleOfGap = (middleBottomInfo.y - (middleTopInfo.y + middleTopInfo.height)) / 2;
                if (element instanceof Task) {
                    y += middleOfGap - (TASK_HEIGHT / 2);
                } else if (element instanceof Gateway) {
                    y += middleOfGap - (GATEWAY_HEIGHT / 2);
                } else if (element instanceof Event) {
                    y += middleOfGap - (EVENT_HEIGHT / 2);
                } else {
                    y += middleOfGap - (TASK_HEIGHT / 2);
                }

            } else {
                throw new FlowSourceNotFoundException();
            }

        } else {
            int middle = ((flowList.size() - 1) / 2);
            if (yMap.containsKey(flowList.get(middle).sourceRef)) {
                GraphicInfo middleInfo = yMap.get(flowList.get(middle).sourceRef);
                if (middleInfo.element instanceof Task) {
                    if (element instanceof Task) {
                        y = middleInfo.y;
                    } else if (element instanceof Gateway) {
                        y = middleInfo.y + 7;
                    } else if (element instanceof Event) {
                        y = middleInfo.y + 10;
                    } else {
                        y = middleInfo.y;
                    }
                } else if (middleInfo.element instanceof Gateway) {
                    if (element instanceof Task) {
                        y = middleInfo.y - 7;
                    } else if (element instanceof Gateway) {
                        y = middleInfo.y;
                    } else if (element instanceof Event) {
                        y = middleInfo.y + 2;
                    } else {
                        y = middleInfo.y - 7;
                    }
                } else if (middleInfo.element instanceof Event) {
                    if (element instanceof Task) {
                        y = middleInfo.y - 10;
                    } else if (element instanceof Gateway) {
                        y = middleInfo.y - 2;
                    } else if (element instanceof Event) {
                        y = middleInfo.y;
                    } else {
                        y = middleInfo.y - 10;
                    }
                } else {
                    y = middleInfo.y;
                }

            } else {
                throw new FlowSourceNotFoundException();
            }
        }
        return y;
    }

    private GraphicInfo getDivergingGateway(FlowElement element, List<SequenceFlowModel> sequenceFlowList,
            String type) {
        for (SequenceFlowModel sequenceFlowModel : sequenceFlowList) {

            if (sequenceFlowModel.targetRef.equals(element.getId())) {

                FlowElement sourceElement = sourceRef(sequenceFlowModel.targetRef, yMap);
                if (sourceElement == null) {
                    throw new FlowSourceNotFoundException();
                }

                if (sourceElement.getClass().getName().equals(type)) {
                    return yMap.get(sourceElement.getId());
                }

                GraphicInfo sourceTreeInfo = getDivergingGateway(sourceElement, sequenceFlowList, type);
                if (sourceTreeInfo != null) {
                    return sourceTreeInfo;
                }
            }
        }
        throw null;
    }

    private int calculateDirectElementChildY(FlowElement element, String id, int elementY,
            List<SequenceFlowModel> sequenceFlowList) {
        int y = 0;
        int counter = 0;
        int index = 0;
        for (SequenceFlowModel sequenceFlowModel : sequenceFlowList) {
            if (sequenceFlowModel.sourceRef.equals(element.getId())) {
                counter++;
            }
            if (sequenceFlowModel.targetRef.equals(id)) {
                index = counter;
            }
        }

        int childHeight = 20;
        if (element instanceof Gateway) {
            childHeight += GATEWAY_HEIGHT;
        } else if (element instanceof Task) {
            childHeight += TASK_HEIGHT;
        } else if (element instanceof Event) {
            childHeight += EVENT_HEIGHT;
        } else {
            childHeight += TASK_HEIGHT;
        }

        if (counter % 2 == 0) {
            if (index > (counter / 2)) {
                y = elementY + ((index - (counter / 2)) * childHeight);
            } else {
                y = elementY - (((counter / 2) - index + 1) * childHeight);
            }
        } else {
            int middle = ((counter - 1) / 2) + 1;
            if (index > middle) {
                y = elementY + ((index - middle) * childHeight);
            } else if (index == middle) {
                y = elementY;
            } else {
                y = elementY - ((middle - index) * childHeight);
            }
        }
        return y;
    }

    private void drawDiagramWithBPMNDI(Diagram diagram, IFeatureProvider featureProvider,
            List<FlowElement> bpmnList, List<SequenceFlowModel> sequenceFlowList,
            Map<String, GraphicInfo> locationMap) {

        for (FlowElement flowElement : bpmnList) {
            String elementid = flowElement.getId();
            GraphicInfo graphicInfo = locationMap.get(elementid);
            addBpmnElementToDiagram(flowElement, graphicInfo, diagram);
        }
        drawSequenceFlows();
    }

    private void setFriendlyIds() {
        Map<String, Integer> idMap = new HashMap<String, Integer>();
        for (FlowElement flowElement : bpmnParser.bpmnList) {
            if (StringUtils.isEmpty(flowElement.getId()) == false && flowElement.getId()
                    .matches("sid-\\w{4,12}-\\w{4,12}-\\w{4,12}-\\w{4,12}-\\w{4,12}") == false) {

                continue;
            }
            if (flowElement instanceof StartEvent) {
                flowElement.setId(getNextId("startevent", idMap));
            } else if (flowElement instanceof EndEvent) {
                if (((EndEvent) flowElement).getEventDefinitions().size() > 0) {
                    flowElement.setId(getNextId("errorendevent", idMap));
                } else {
                    flowElement.setId(getNextId("endevent", idMap));
                }
            } else if (flowElement instanceof ExclusiveGateway) {
                flowElement.setId(getNextId("exclusivegateway", idMap));
            } else if (flowElement instanceof InclusiveGateway) {
                flowElement.setId(getNextId("inclusivegateway", idMap));
            } else if (flowElement instanceof ParallelGateway) {
                flowElement.setId(getNextId("parallelgateway", idMap));
            } else if (flowElement instanceof UserTask) {
                flowElement.setId(getNextId("usertask", idMap));
            } else if (flowElement instanceof ScriptTask) {
                flowElement.setId(getNextId("scripttask", idMap));
            } else if (flowElement instanceof ServiceTask) {
                flowElement.setId(getNextId("servicetask", idMap));
            } else if (flowElement instanceof ManualTask) {
                flowElement.setId(getNextId("manualtask", idMap));
            } else if (flowElement instanceof ReceiveTask) {
                flowElement.setId(getNextId("receivetask", idMap));
            } else if (flowElement instanceof BusinessRuleTask) {
                flowElement.setId(getNextId("businessruletask", idMap));
            } else if (flowElement instanceof MailTask) {
                flowElement.setId(getNextId("mailtask", idMap));
            } else if (flowElement instanceof BoundaryEvent) {
                if (((BoundaryEvent) flowElement).getEventDefinitions().size() > 0) {
                    EventDefinition definition = ((BoundaryEvent) flowElement).getEventDefinitions().get(0);
                    if (definition instanceof ErrorEventDefinition) {
                        flowElement.setId(getNextId("boundaryerror", idMap));
                    } else {
                        flowElement.setId(getNextId("boundarytimer", idMap));
                    }
                }
            } else if (flowElement instanceof CallActivity) {
                flowElement.setId(getNextId("callactivity", idMap));
            } else if (flowElement instanceof SubProcess) {
                flowElement.setId(getNextId("subprocess", idMap));
            }
        }
    }

    private String getNextId(String elementName, Map<String, Integer> idMap) {
        if (idMap.containsKey(elementName)) {
            idMap.put(elementName, idMap.get(elementName) + 1);
        } else {
            idMap.put(elementName, 1);
        }
        return elementName + idMap.get(elementName);
    }

    private void drawSequenceFlows() {
        int sequenceCounter = 1;
        for (SequenceFlowModel sequenceFlowModel : bpmnParser.sequenceFlowList) {
            SequenceFlow sequenceFlow = Bpmn2Factory.eINSTANCE.createSequenceFlow();
            if (StringUtils.isEmpty(sequenceFlowModel.id)
                    || sequenceFlowModel.id.matches("sid-\\w{4,12}-\\w{4,12}-\\w{4,12}-\\w{4,12}-\\w{4,12}")) {
                sequenceFlow.setId("flow" + sequenceCounter);
                sequenceCounter++;
            } else {
                sequenceFlow.setId(sequenceFlowModel.id);
            }
            sequenceFlow.setSourceRef(getFlowNode(sequenceFlowModel.sourceRef));
            sequenceFlow.setTargetRef(getFlowNode(sequenceFlowModel.targetRef));
            if (sequenceFlow.getSourceRef() == null || sequenceFlow.getSourceRef().getId() == null
                    || sequenceFlow.getTargetRef() == null || sequenceFlow.getTargetRef().getId() == null)
                continue;
            if (sequenceFlowModel.conditionExpression != null) {
                sequenceFlow.setConditionExpression(sequenceFlowModel.conditionExpression);
            }
            if (sequenceFlowModel.listenerList.size() > 0) {
                sequenceFlow.getExecutionListeners().addAll(sequenceFlowModel.listenerList);
            }

            ContainerShape parent = null;
            SubProcess subProcess = subProcessContains(sequenceFlow.getSourceRef(), subProcessList);
            if (subProcess != null) {
                ILinkService linkService = Graphiti.getLinkService();
                List<PictogramElement> pictoList = linkService.getPictogramElements(diagram, subProcess);
                if (pictoList != null && pictoList.size() > 0) {
                    parent = (ContainerShape) pictoList.get(0);
                    subProcess.getFlowElements().add(sequenceFlow);
                }
            }

            if (parent == null) {
                diagram.eResource().getContents().add(sequenceFlow);
                parent = diagram;
            }

            sequenceFlow.getSourceRef().getOutgoing().add(sequenceFlow);
            sequenceFlow.getTargetRef().getIncoming().add(sequenceFlow);

            EList<Shape> shapeList = parent.getChildren();
            ILinkService linkService = Graphiti.getLinkService();
            Anchor sourceAnchor = null;
            Anchor targetAnchor = null;
            for (Shape shape : shapeList) {
                FlowNode flowNode = (FlowNode) linkService.getBusinessObjectForLinkedPictogramElement(
                        shape.getGraphicsAlgorithm().getPictogramElement());
                if (flowNode == null || flowNode.getId() == null)
                    continue;

                if (sequenceFlow.getSourceRef() instanceof BoundaryEvent) {
                    if (flowNode instanceof Task || flowNode instanceof SubProcess) {
                        for (Shape subShape : ((ContainerShape) shape).getChildren()) {
                            FlowNode subFlowNode = (FlowNode) linkService
                                    .getBusinessObjectForLinkedPictogramElement(
                                            subShape.getGraphicsAlgorithm().getPictogramElement());
                            if (subFlowNode == null || subFlowNode.getId() == null)
                                continue;

                            if (subFlowNode.getId().equals(sequenceFlow.getSourceRef().getId())) {
                                EList<Anchor> anchorList = ((ContainerShape) subShape).getAnchors();
                                for (Anchor anchor : anchorList) {
                                    if (anchor instanceof ChopboxAnchor) {
                                        sourceAnchor = anchor;
                                        break;
                                    }
                                }
                            }
                        }
                    }

                } else {

                    if (flowNode.getId().equals(sequenceFlow.getSourceRef().getId())) {
                        EList<Anchor> anchorList = ((ContainerShape) shape).getAnchors();
                        for (Anchor anchor : anchorList) {
                            if (anchor instanceof ChopboxAnchor) {
                                sourceAnchor = anchor;
                                break;
                            }
                        }
                    }
                }

                if (flowNode.getId().equals(sequenceFlow.getTargetRef().getId())) {
                    EList<Anchor> anchorList = ((ContainerShape) shape).getAnchors();
                    for (Anchor anchor : anchorList) {
                        if (anchor instanceof ChopboxAnchor) {
                            targetAnchor = anchor;
                            break;
                        }
                    }
                }
            }

            AddConnectionContext addContext = new AddConnectionContext(sourceAnchor, targetAnchor);

            if (useBPMNDI) {
                List<GraphicInfo> bendpointList = new ArrayList<GraphicInfo>();
                for (String sequenceGraphElement : bpmnParser.flowLocationMap.keySet()) {
                    if (sequenceFlowModel.id.equalsIgnoreCase(sequenceGraphElement)) {
                        List<GraphicInfo> pointList = bpmnParser.flowLocationMap.get(sequenceGraphElement);
                        if (pointList.size() > 2) {
                            for (int i = 1; i < pointList.size() - 1; i++) {
                                bendpointList.add(pointList.get(i));
                            }
                        }
                    }
                }

                addContext.putProperty("org.activiti.designer.bendpoints", bendpointList);
            }

            addContext.setNewObject(sequenceFlow);
            featureProvider.addIfPossible(addContext);

            if (bpmnParser.defaultFlowMap.containsValue(sequenceFlowModel.id)) {
                Iterator<FlowNode> itDefaultFlow = bpmnParser.defaultFlowMap.keySet().iterator();
                while (itDefaultFlow.hasNext()) {
                    FlowNode flowNode = itDefaultFlow.next();
                    String defaultId = bpmnParser.defaultFlowMap.get(flowNode);
                    if (defaultId.equalsIgnoreCase(sequenceFlowModel.id)) {
                        if (flowNode instanceof ExclusiveGateway) {
                            ((ExclusiveGateway) flowNode).setDefault(sequenceFlow);
                        } else if (flowNode instanceof InclusiveGateway) {
                            ((InclusiveGateway) flowNode).setDefault(sequenceFlow);
                        } else {
                            ((Activity) flowNode).setDefault(sequenceFlow);
                        }
                    }
                }
            }
        }
    }

    private SubProcess subProcessContains(FlowNode sourceRef, List<SubProcess> subProcessList) {
        for (SubProcess subProcess : subProcessList) {
            for (FlowElement flowElement : subProcess.getFlowElements()) {
                if (flowElement.getId().equals(sourceRef.getId())) {
                    return subProcess;
                }
            }
        }
        return null;
    }

    private FlowNode getFlowNode(String elementid) {
        FlowNode flowNode = null;
        for (FlowElement flowElement : bpmnParser.bpmnList) {
            if (flowElement.getId().equalsIgnoreCase(elementid)) {
                flowNode = (FlowNode) flowElement;
            }
        }
        return flowNode;
    }

    private void addBpmnElementToDiagram(FlowElement flowElement, GraphicInfo graphicInfo, ContainerShape parent) {

        if (flowElement instanceof BoundaryEvent) {
            BoundaryEvent boundaryEvent = (BoundaryEvent) flowElement;
            AddContext addContext = new AddContext();
            boolean parentIsSubProcess = false;

            if (boundaryEvent.getAttachedToRef() instanceof SubProcess) {
                parentIsSubProcess = true;
            }

            ILinkService linkService = Graphiti.getLinkService();
            List<PictogramElement> pictoList = linkService.getPictogramElements(diagram,
                    boundaryEvent.getAttachedToRef());
            if (pictoList != null && pictoList.size() > 0) {
                addContext.setTargetContainer((ContainerShape) pictoList.get(0));
            }

            addContext.setNewObject(boundaryEvent);
            if (parentIsSubProcess == true) {
                addContext.setX(addContext.getTargetContainer().getGraphicsAlgorithm().getWidth() / 2);
                addContext.setY(addContext.getTargetContainer().getGraphicsAlgorithm().getHeight() - 15);
            } else {
                addContext.setX(TASK_WIDTH - 25);
                addContext.setY(TASK_HEIGHT - 25);
            }

            IAddFeature addFeature = featureProvider.getAddFeature(addContext);
            if (addFeature.canAdd(addContext)) {
                addFeature.add(addContext);
            }
            return;
        }

        if (flowElement instanceof UserTask) {
            UserTask userTask = (UserTask) flowElement;
            if (userTask.getCandidateUsers() != null && userTask.getCandidateUsers().size() > 0) {
                for (CandidateUser candidateUser : userTask.getCandidateUsers()) {
                    diagram.eResource().getContents().add(candidateUser);
                }
            }
            if (userTask.getCandidateGroups() != null && userTask.getCandidateGroups().size() > 0) {
                for (CandidateGroup candidateGroup : userTask.getCandidateGroups()) {
                    diagram.eResource().getContents().add(candidateGroup);
                }
            }
        } else if (flowElement instanceof ServiceTask) {
            ServiceTask serviceTask = (ServiceTask) flowElement;
            if (serviceTask.getFieldExtensions() != null && serviceTask.getFieldExtensions().size() > 0) {
                for (FieldExtension fieldExtension : serviceTask.getFieldExtensions()) {
                    diagram.eResource().getContents().add(fieldExtension);
                }
            }
        }

        AddContext addContext = new AddContext();
        addContext.setNewObject(flowElement);
        addContext.setTargetContainer(parent);
        addContext.setX(graphicInfo.x);

        if (useBPMNDI) {
            addContext.setHeight(graphicInfo.height);
            addContext.setWidth(graphicInfo.width);
        }

        if (flowElement instanceof StartEvent || flowElement instanceof EndEvent) {
            if (useBPMNDI == false && graphicInfo.height < EVENT_HEIGHT) {
                addContext.setY(graphicInfo.y - 25);
            } else {
                addContext.setY(graphicInfo.y);
            }
        } else if (flowElement instanceof ExclusiveGateway || flowElement instanceof InclusiveGateway
                || flowElement instanceof ParallelGateway) {
            if (useBPMNDI == false && graphicInfo.height < GATEWAY_HEIGHT) {
                addContext.setY(graphicInfo.y - 20);
            } else {
                addContext.setY(graphicInfo.y);
            }
        } else if (flowElement instanceof SubProcess) {
            addContext.setHeight(graphicInfo.height);
            addContext.setWidth(graphicInfo.width);
            addContext.setY(graphicInfo.y);
        } else {
            addContext.setY(graphicInfo.y);
        }

        IAddFeature addFeature = featureProvider.getAddFeature(addContext);
        if (addFeature.canAdd(addContext)) {
            addFeature.add(addContext);
        }
    }
}