/*******************************************************************************
* Copyright (c) 2011 Red Hat, Inc.
* All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.eclipse.bpmn2.modeler.core;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.bpmn2.Artifact;
import org.eclipse.bpmn2.Association;
import org.eclipse.bpmn2.BaseElement;
import org.eclipse.bpmn2.Bpmn2Factory;
import org.eclipse.bpmn2.Collaboration;
import org.eclipse.bpmn2.ConversationLink;
import org.eclipse.bpmn2.ConversationNode;
import org.eclipse.bpmn2.DataInput;
import org.eclipse.bpmn2.DataOutput;
import org.eclipse.bpmn2.Definitions;
import org.eclipse.bpmn2.DocumentRoot;
import org.eclipse.bpmn2.FlowElement;
import org.eclipse.bpmn2.FlowElementsContainer;
import org.eclipse.bpmn2.FlowNode;
import org.eclipse.bpmn2.InputOutputSpecification;
import org.eclipse.bpmn2.InteractionNode;
import org.eclipse.bpmn2.Lane;
import org.eclipse.bpmn2.LaneSet;
import org.eclipse.bpmn2.MessageFlow;
import org.eclipse.bpmn2.Participant;
import org.eclipse.bpmn2.Process;
import org.eclipse.bpmn2.RootElement;
import org.eclipse.bpmn2.SequenceFlow;
import org.eclipse.bpmn2.di.BPMNDiagram;
import org.eclipse.bpmn2.di.BPMNEdge;
import org.eclipse.bpmn2.di.BPMNShape;
import org.eclipse.bpmn2.modeler.core.features.BusinessObjectUtil;
import org.eclipse.bpmn2.modeler.core.utils.ModelUtil;
import org.eclipse.bpmn2.util.Bpmn2ResourceImpl;
import org.eclipse.dd.di.DiagramElement;
import org.eclipse.emf.common.util.ECollections;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.graphiti.mm.pictograms.Diagram;
import org.eclipse.graphiti.mm.pictograms.PictogramElement;
import org.eclipse.graphiti.mm.pictograms.Shape;
public class ModelHandler {
public static final Bpmn2Factory FACTORY = Bpmn2Factory.eINSTANCE;
Bpmn2ResourceImpl resource;
ModelHandler() {
}
void createDefinitionsIfMissing() {
EList<EObject> contents = resource.getContents();
if (contents.isEmpty() || !(contents.get(0) instanceof DocumentRoot)) {
TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(resource);
if (domain != null) {
final DocumentRoot docRoot = FACTORY.createDocumentRoot();
final Definitions definitions = FACTORY.createDefinitions();
// definitions.setId(EcoreUtil.generateUUID());
ModelUtil.setID(definitions,resource);
Collaboration collaboration = FACTORY.createCollaboration();
// collaboration.setId(EcoreUtil.generateUUID());
ModelUtil.setID(collaboration,resource);
Participant participant = FACTORY.createParticipant();
// participant.setId(EcoreUtil.generateUUID());
ModelUtil.setID(participant,resource);
participant.setName("Internal");
collaboration.getParticipants().add(participant);
definitions.getRootElements().add(collaboration);
domain.getCommandStack().execute(new RecordingCommand(domain) {
@Override
protected void doExecute() {
docRoot.setDefinitions(definitions);
resource.getContents().add(docRoot);
}
});
return;
}
}
}
public static ModelHandler getInstance(Diagram diagram) throws IOException {
return ModelHandlerLocator.getModelHandler(diagram.eResource());
}
/**
* @param <T>
* @param target
* object that this element is being added to
* @param elem
* flow element to be added
* @return
*/
public <T extends FlowElement> T addFlowElement(Object target, T elem) {
FlowElementsContainer container = getFlowElementContainer(target);
container.getFlowElements().add(elem);
return elem;
}
/**
* @param <A>
* @param target
* object that this artifact is being added to
* @param artifact
* artifact to be added
* @return
*/
public <T extends Artifact> T addArtifact(Object target, T artifact) {
Process process = getOrCreateProcess(getParticipant(target));
process.getArtifacts().add(artifact);
return artifact;
}
public <T extends RootElement> T addRootElement(T element) {
getDefinitions().getRootElements().add(element);
return element;
}
public DataOutput addDataOutput(Object target, DataOutput dataOutput) {
getOrCreateIOSpecification(target).getDataOutputs().add(dataOutput);
return dataOutput;
}
public DataInput addDataInput(Object target, DataInput dataInput) {
getOrCreateIOSpecification(target).getDataInputs().add(dataInput);
return dataInput;
}
public ConversationNode addConversationNode(ConversationNode conversationNode) {
getOrCreateCollaboration().getConversations().add(conversationNode);
return conversationNode;
}
private InputOutputSpecification getOrCreateIOSpecification(Object target) {
Process process = getOrCreateProcess(getParticipant(target));
if (process.getIoSpecification() == null) {
InputOutputSpecification ioSpec = FACTORY.createInputOutputSpecification();
// ioSpec.setId(EcoreUtil.generateUUID());
ModelUtil.setID(ioSpec,resource);
process.setIoSpecification(ioSpec);
}
return process.getIoSpecification();
}
public void moveFlowNode(FlowNode node, Object source, Object target) {
FlowElementsContainer sourceContainer = getFlowElementContainer(source);
FlowElementsContainer targetContainer = getFlowElementContainer(target);
sourceContainer.getFlowElements().remove(node);
targetContainer.getFlowElements().add(node);
for (SequenceFlow flow : node.getOutgoing()) {
sourceContainer.getFlowElements().remove(flow);
targetContainer.getFlowElements().add(flow);
}
}
public Participant addParticipant() {
Collaboration collaboration = getOrCreateCollaboration();
Participant participant = FACTORY.createParticipant();
// participant.setId(EcoreUtil.generateUUID());
ModelUtil.setID(participant,resource);
collaboration.getParticipants().add(participant);
return participant;
}
@Deprecated
public void moveLane(Lane movedLane, Participant targetParticipant) {
Participant sourceParticipant = getParticipant(movedLane);
moveLane(movedLane, sourceParticipant, targetParticipant);
}
public void moveLane(Lane movedLane, Participant sourceParticipant, Participant targetParticipant) {
Process sourceProcess = getOrCreateProcess(sourceParticipant);
Process targetProcess = getOrCreateProcess(targetParticipant);
for (FlowNode node : movedLane.getFlowNodeRefs()) {
moveFlowNode(node, sourceProcess, targetProcess);
}
if (movedLane.getChildLaneSet() != null && !movedLane.getChildLaneSet().getLanes().isEmpty()) {
for (Lane lane : movedLane.getChildLaneSet().getLanes()) {
moveLane(lane, sourceParticipant, targetParticipant);
}
}
}
public Process getOrCreateProcess(Participant participant) {
if (participant.getProcessRef() == null) {
Process process = FACTORY.createProcess();
// process.setId(EcoreUtil.generateUUID());
ModelUtil.setID(process,resource);
process.setName("Process for " + participant.getName());
getDefinitions().getRootElements().add(process);
participant.setProcessRef(process);
}
return participant.getProcessRef();
}
public Lane createLane(Lane targetLane) {
Lane lane = FACTORY.createLane();
// lane.setId(EcoreUtil.generateUUID());
ModelUtil.setID(lane,resource);
if (targetLane.getChildLaneSet() == null) {
targetLane.setChildLaneSet(ModelHandler.FACTORY.createLaneSet());
}
LaneSet targetLaneSet = targetLane.getChildLaneSet();
targetLaneSet.getLanes().add(lane);
lane.getFlowNodeRefs().addAll(targetLane.getFlowNodeRefs());
targetLane.getFlowNodeRefs().clear();
return lane;
}
public Lane createLane(Object target) {
Lane lane = FACTORY.createLane();
// lane.setId(EcoreUtil.generateUUID());
ModelUtil.setID(lane,resource);
FlowElementsContainer container = getFlowElementContainer(target);
if (container.getLaneSets().isEmpty()) {
LaneSet laneSet = FACTORY.createLaneSet();
// laneSet.setId(EcoreUtil.generateUUID());
container.getLaneSets().add(laneSet);
}
container.getLaneSets().get(0).getLanes().add(lane);
ModelUtil.setID(lane);
return lane;
}
public void laneToTop(Lane lane) {
LaneSet laneSet = FACTORY.createLaneSet();
// laneSet.setId(EcoreUtil.generateUUID());
ModelUtil.setID(laneSet,resource);
laneSet.getLanes().add(lane);
Process process = getOrCreateProcess(getInternalParticipant());
process.getLaneSets().add(laneSet);
}
public SequenceFlow createSequenceFlow(FlowNode source, FlowNode target) {
SequenceFlow sequenceFlow = FACTORY.createSequenceFlow();
// sequenceFlow.setId(EcoreUtil.generateUUID());
ModelUtil.setID(sequenceFlow,resource);
addFlowElement(source, sequenceFlow);
sequenceFlow.setSourceRef(source);
sequenceFlow.setTargetRef(target);
return sequenceFlow;
}
public MessageFlow createMessageFlow(InteractionNode source, InteractionNode target) {
MessageFlow messageFlow = FACTORY.createMessageFlow();
// messageFlow.setId(EcoreUtil.generateUUID());
ModelUtil.setID(messageFlow,resource);
messageFlow.setSourceRef(source);
messageFlow.setTargetRef(target);
getOrCreateCollaboration().getMessageFlows().add(messageFlow);
return messageFlow;
}
public ConversationLink createConversationLink(InteractionNode source, InteractionNode target) {
ConversationLink link = FACTORY.createConversationLink();
link.setSourceRef(source);
link.setTargetRef(target);
getOrCreateCollaboration().getConversationLinks().add(link);
return link;
}
public Association createAssociation(BaseElement source, BaseElement target) {
BaseElement e = null;
if (getParticipant(source) != null) {
e = source;
} else if (getParticipant(target) != null) {
e = target;
} else {
e = getInternalParticipant();
}
Association association = FACTORY.createAssociation();
addArtifact(e, association);
// association.setId(EcoreUtil.generateUUID());
ModelUtil.setID(association,resource);
association.setSourceRef(source);
association.setTargetRef(target);
return association;
}
private Collaboration getOrCreateCollaboration() {
final List<RootElement> rootElements = getDefinitions().getRootElements();
for (RootElement element : rootElements) {
if (element instanceof Collaboration) {
return (Collaboration) element;
}
}
TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(resource);
final Collaboration collaboration = FACTORY.createCollaboration();
// collaboration.setId(EcoreUtil.generateUUID());
ModelUtil.setID(collaboration,resource);
if (domain != null) {
domain.getCommandStack().execute(new RecordingCommand(domain) {
@Override
protected void doExecute() {
addCollaborationToRootElements(rootElements, collaboration);
}
});
}
return collaboration;
}
private void addCollaborationToRootElements(final List<RootElement> rootElements, final Collaboration collaboration) {
Participant participant = FACTORY.createParticipant();
// participant.setId(EcoreUtil.generateUUID());
ModelUtil.setID(participant,resource);
participant.setName("Internal");
for (RootElement element : rootElements) {
if (element instanceof Process) {
participant.setProcessRef((Process) element);
break;
}
}
collaboration.getParticipants().add(participant);
rootElements.add(collaboration);
}
public Bpmn2ResourceImpl getResource() {
return resource;
}
public Definitions getDefinitions() {
return (Definitions) resource.getContents().get(0).eContents().get(0);
}
public void save() {
TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(resource);
if (domain != null) {
domain.getCommandStack().execute(new RecordingCommand(domain) {
@Override
protected void doExecute() {
saveResource();
}
});
} else {
saveResource();
}
}
private void saveResource() {
fixZOrder();
try {
resource.save(null);
} catch (IOException e) {
Activator.logError(e);
}
}
private void fixZOrder() {
final List<BPMNDiagram> diagrams = getAll(BPMNDiagram.class);
for (BPMNDiagram bpmnDiagram : diagrams) {
fixZOrder(bpmnDiagram);
}
}
private void fixZOrder(BPMNDiagram bpmnDiagram) {
EList<DiagramElement> elements = (EList<DiagramElement>) bpmnDiagram.getPlane().getPlaneElement();
ECollections.sort(elements, new DIZorderComparator());
}
void loadResource() {
try {
resource.load(null);
} catch (IOException e) {
Activator.logError(e);
}
}
public Participant getInternalParticipant() {
return getOrCreateCollaboration().getParticipants().get(0);
}
public FlowElementsContainer getFlowElementContainer(Object o) {
if (o == null || o instanceof BPMNDiagram) {
return getOrCreateProcess(getInternalParticipant());
}
if (o instanceof Participant) {
return getOrCreateProcess((Participant) o);
}
return findElementOfType(FlowElementsContainer.class, o);
}
public Participant getParticipant(final Object o) {
if (o == null || o instanceof Diagram) {
return getInternalParticipant();
}
Object object = o;
if (o instanceof Shape) {
object = BusinessObjectUtil.getFirstElementOfType((PictogramElement) o, BaseElement.class);
}
if (object instanceof Participant) {
return (Participant) object;
}
Process process = findElementOfType(Process.class, object);
for (Participant p : getOrCreateCollaboration().getParticipants()) {
if (p.getProcessRef() != null && p.getProcessRef().equals(process)) {
return p;
}
}
return getInternalParticipant();
}
@SuppressWarnings("unchecked")
public <T extends BaseElement> T findElementOfType(Class<T> clazz, Object from) {
if (!(from instanceof BaseElement)) {
return null;
}
if (clazz.isAssignableFrom(from.getClass())) {
return (T) from;
}
return findElementOfType(clazz, ((BaseElement) from).eContainer());
}
@SuppressWarnings("unchecked")
public <T> List<T> getAll(final Class<T> class1) {
ArrayList<T> l = new ArrayList<T>();
TreeIterator<EObject> contents = resource.getAllContents();
for (; contents.hasNext();) {
Object t = contents.next();
if (class1.isInstance(t)) {
l.add((T) t);
}
}
return l;
}
public DiagramElement findDIElement(Diagram diagram, BaseElement element) {
List<BPMNDiagram> diagrams = getAll(BPMNDiagram.class);
for (BPMNDiagram d : diagrams) {
List<DiagramElement> planeElement = d.getPlane().getPlaneElement();
for (DiagramElement elem : planeElement) {
if (elem instanceof BPMNShape && element.getId() != null
&& element.getId().equals(((BPMNShape) elem).getBpmnElement().getId())) {
return (elem);
} else if (elem instanceof BPMNEdge && element.getId() != null
&& element.getId().equals(((BPMNEdge) elem).getBpmnElement().getId())) {
return (elem);
}
}
}
return null;
}
}