Skip to content

Commit

Permalink
impl, added junit tests
Browse files Browse the repository at this point in the history
Issue imixs#233
  • Loading branch information
rsoika committed Apr 18, 2023
1 parent d14cfec commit bc2b81a
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ protected void executeOperation(PasteOperation operation) {
BPMNElementNode bpmnElementNode = modelState.getBpmnModel().findElementNodeById(id);
if (bpmnElementNode != null) {
try {
// close BPMNElementNodes....
// clone BPMNElementNodes....
BPMNProcess process = modelState.getBpmnModel().openProcess(bpmnElementNode.getProcessId());
BPMNElementNode newElementNode = process.cloneBPMNElementNode(bpmnElementNode);
if (newElementNode != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1187,11 +1187,18 @@ public BPMNElementNode cloneBPMNElementNode(BPMNElementNode _bpmnElementNode) th
Element element = (Element) this.getElementNode().appendChild(newElement);
result = this.createBPMNTextAnnotationByNode(element);
}
// if (_bpmnElementNode instanceof Message) {
// newElement.setAttribute("id", BPMNModel.generateShortID("message"));
// Element element = (Element) this.getElementNode().appendChild(newElement);
// result = this.getModel()..createBPMNMessageByNode(element);
// }

// cleanup invalid flow references
result.updateSequenceFlowReferences();

// update alls id of bpmn2:documentation childs
NodeList documentationList = this.getElementNode()
.getElementsByTagName(this.getModel().getPrefix(BPMNNS.BPMN2) + ":documentation");
for (int i = 0; i < documentationList.getLength(); i++) {
Element item = (Element) documentationList.item(i);
// update id....
item.setAttribute("id", BPMNModel.generateShortID("documentation"));
}

return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.stream.Collectors;

import org.openbpmn.bpmn.BPMNModel;
import org.openbpmn.bpmn.BPMNNS;
import org.openbpmn.bpmn.BPMNTypes;
import org.openbpmn.bpmn.elements.Activity;
import org.openbpmn.bpmn.elements.Association;
Expand All @@ -18,6 +19,7 @@
import org.openbpmn.bpmn.exceptions.BPMNMissingElementException;
import org.openbpmn.bpmn.exceptions.BPMNModelException;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
* The BPMNNode is the abstract super class for most BPMN elements like Task,
Expand Down Expand Up @@ -233,6 +235,50 @@ public void updateBPMNProcess(BPMNProcess newProcess) throws BPMNInvalidTypeExce
this.bpmnProcess.elementNode.appendChild(this.elementNode);
}

/**
* This method updates the bpmn2:incoming and bpmn2:outgoing references of a
* BPMNElement.
* During cloning a element it may happen that invalid references are copied as
* child elements. This method can be called to clean up such references.
*
*/
public void updateSequenceFlowReferences() {
// only possible if a bpmnProcess is defined
if (bpmnProcess == null) {
return; // no op!
}
// remove incoming childs...
NodeList incomingSequenceFlows = getElementNode()
.getElementsByTagName(bpmnProcess.getModel().getPrefix(BPMNNS.BPMN2) + ":incoming");
for (int i = 0; i < incomingSequenceFlows.getLength(); i++) {
Element item = (Element) incomingSequenceFlows.item(i);
// test if the sequence flow exists...
BPMNElementEdge flow = bpmnProcess.findElementEdgeById(item.getTextContent());
if (flow != null &&
(!getId().equals(flow.getElementNode().getAttribute("sourceRef"))
&& !getId().equals(flow.getElementNode().getAttribute("targetRef")))) {
// invalid element
getElementNode().removeChild(item);
}

}
// remove outgoing childs...
NodeList outgoingSequenceFlows = getElementNode()
.getElementsByTagName(bpmnProcess.getModel().getPrefix(BPMNNS.BPMN2) + ":outgoing");
for (int i = 0; i < outgoingSequenceFlows.getLength(); i++) {
Element item = (Element) outgoingSequenceFlows.item(i);
// test if the sequence flow exists...
BPMNElementEdge flow = bpmnProcess.findElementEdgeById(item.getTextContent());
if (flow != null &&
(!getId().equals(flow.getElementNode().getAttribute("sourceRef"))
&& !getId().equals(flow.getElementNode().getAttribute("targetRef")))) {
// invalid element
getElementNode().removeChild(item);
}
}

}

public void setDimension(double width, double height) {
try {
this.getBounds().setDimension(width, height);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package org.openbpmn.metamodel.test.elements;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.fail;

import java.util.logging.Logger;

import org.junit.jupiter.api.Test;
import org.openbpmn.bpmn.BPMNModel;
import org.openbpmn.bpmn.elements.BPMNProcess;
import org.openbpmn.bpmn.elements.core.BPMNElementNode;
import org.openbpmn.bpmn.exceptions.BPMNModelException;
import org.openbpmn.bpmn.util.BPMNModelFactory;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
* This test class reads a BPMN Model instance and copies (clones) elements.
* This is happening in the modeller during copy/paste actions.
*
* @author rsoika
*
*/
public class TestCloneFlowElements {

private static Logger logger = Logger.getLogger(TestCloneFlowElements.class.getName());

/**
* This test parses a bpmn file
*/
@Test
public void testReadEmptyModel() {

logger.info("...read model");
try {
String out = "src/test/resources/output/clone-refmodel-1.bpmn";
BPMNModel model = BPMNModelFactory.read("/refmodel-1.bpmn");

// copy Task_1
// The expectation here is that the incoming and outcoming sequence flows will
// be removed from the copy and the documentation element gets a new id

BPMNProcess process = model.openProcess(null);

assertNotNull(process);

BPMNElementNode originTask = process.findElementNodeById("Task_1");

// clone....
BPMNElementNode clonedTask = process.cloneBPMNElementNode(originTask);

assertNotNull(clonedTask);
clonedTask.setName("Copy of Task 1");

// The id from the documentation must be changed!
NodeList originDocumentationElements = originTask.getElementNode()
.getElementsByTagName("bpmn2:documentation");
NodeList clonedDocumentationElements = clonedTask.getElementNode()
.getElementsByTagName("bpmn2:documentation");
assertNotNull(clonedDocumentationElements);
assertEquals(1, clonedDocumentationElements.getLength());
// compare IDs
Element originDocNode = (Element) originDocumentationElements.item(0);
Element clonedDocNode = (Element) clonedDocumentationElements.item(0);
assertNotEquals(originDocNode.getAttribute("id"), clonedDocNode.getAttribute("id"));

// next we expect no outgoing and incoming sequenceFlows...

NodeList incomingSequenceFlows = clonedTask.getElementNode()
.getElementsByTagName("bpmn2:incoming");
NodeList outgoingSequenceFlows = clonedTask.getElementNode()
.getElementsByTagName("bpmn2:outgoing");

assertEquals(0, incomingSequenceFlows.getLength());
assertEquals(0, outgoingSequenceFlows.getLength());

assertEquals(0, clonedTask.getIngoingSequenceFlows().size());
assertEquals(0, clonedTask.getOutgoingSequenceFlows().size());

// finally write the output...
// we expect that this new model can be opened with other modellers like
// Eclipse-BPMN2
model.save(out);

} catch (BPMNModelException e) {
e.printStackTrace();
fail();
}
logger.info("...task cloned successful");
}

}
63 changes: 35 additions & 28 deletions open-bpmn.metamodel/src/test/resources/refmodel-1.bpmn
Original file line number Diff line number Diff line change
@@ -1,74 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- origin at X=0.0 Y=0.0 -->
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:ext="http://org.eclipse.bpmn2/ext" xmlns:xs="http://www.w3.org/2001/XMLSchema" id="Definitions_1" exporter="org.eclipse.bpmn2.modeler.core" exporterVersion="1.5.3.Final-v20210519-2007-B1" targetNamespace="http://org.eclipse.bpmn2/default/process">
<bpmn2:process id="process_1" name="Default Process" isExecutable="false">
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- origin at X=0.0 Y=0.0 --><bpmn2:definitions xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:ext="http://org.eclipse.bpmn2/ext" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exporter="org.eclipse.bpmn2.modeler.core" exporterVersion="1.5.3.Final-v20210519-2007-B1" id="Definitions_1" targetNamespace="http://org.eclipse.bpmn2/default/process">
<bpmn2:process id="process_1" isExecutable="false" name="Default Process" processType="Public">
<bpmn2:startEvent id="StartEvent_1" name="Start Event 1">
<bpmn2:outgoing>SequenceFlow_1</bpmn2:outgoing>
<bpmn2:documentation id="documentation_RpGdkQ"/>
</bpmn2:startEvent>
<bpmn2:sequenceFlow id="SequenceFlow_1" name="Sequence Flow 1" sourceRef="StartEvent_1" targetRef="Task_1"/>
<bpmn2:sequenceFlow id="SequenceFlow_1" name="Sequence Flow 1" sourceRef="StartEvent_1" targetRef="Task_1">
<bpmn2:documentation id="documentation_wMvUQA"/>
</bpmn2:sequenceFlow>
<bpmn2:endEvent id="EndEvent_1" name="End Event 1">
<bpmn2:incoming>SequenceFlow_5</bpmn2:incoming>
<bpmn2:documentation id="documentation_QZZ1fA"/>
</bpmn2:endEvent>
<bpmn2:task id="Task_1" name="Task 1">
<bpmn2:incoming>SequenceFlow_1</bpmn2:incoming>
<bpmn2:outgoing>SequenceFlow_4</bpmn2:outgoing>
<bpmn2:documentation id="documentation_8u2JXA"><![CDATA[Some Documentation]]></bpmn2:documentation>
</bpmn2:task>
<bpmn2:sendTask id="SendTask_1" name="Send Task 1">
<bpmn2:incoming>SequenceFlow_4</bpmn2:incoming>
<bpmn2:outgoing>SequenceFlow_5</bpmn2:outgoing>
<bpmn2:documentation id="documentation_eWxjJw"><![CDATA[Another Documentation]]></bpmn2:documentation>
</bpmn2:sendTask>
<bpmn2:sequenceFlow id="SequenceFlow_4" sourceRef="Task_1" targetRef="SendTask_1"/>
<bpmn2:sequenceFlow id="SequenceFlow_5" sourceRef="SendTask_1" targetRef="EndEvent_1"/>
<bpmn2:sequenceFlow id="SequenceFlow_4" sourceRef="Task_1" targetRef="SendTask_1">
<bpmn2:documentation id="documentation_rGoN0w"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="SequenceFlow_5" sourceRef="SendTask_1" targetRef="EndEvent_1">
<bpmn2:documentation id="documentation_4A640g"/>
</bpmn2:sequenceFlow>
<bpmn2:documentation id="documentation_iHHZ0g"/>
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1" name="Default Process Diagram">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="process_1">
<bpmndi:BPMNShape id="BPMNShape_1" bpmnElement="StartEvent_1">
<bpmndi:BPMNPlane bpmnElement="process_1" id="BPMNPlane_1">
<bpmndi:BPMNShape bpmnElement="StartEvent_1" id="BPMNShape_1">
<dc:Bounds height="36.0" width="36.0" x="100.0" y="100.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_1" labelStyle="BPMNLabelStyle_1">
<dc:Bounds height="14.0" width="69.0" x="84.0" y="136.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_2" bpmnElement="EndEvent_1">
<bpmndi:BPMNShape bpmnElement="EndEvent_1" id="BPMNShape_2">
<dc:Bounds height="36.0" width="36.0" x="572.0" y="261.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_3" labelStyle="BPMNLabelStyle_1">
<dc:Bounds height="14.0" width="66.0" x="557.0" y="297.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_Task_1" bpmnElement="Task_1" isExpanded="true">
<bpmndi:BPMNShape bpmnElement="Task_1" id="BPMNShape_Task_1" isExpanded="true">
<dc:Bounds height="50.0" width="110.0" x="270.0" y="149.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_4" labelStyle="BPMNLabelStyle_1">
<dc:Bounds height="14.0" width="35.0" x="307.0" y="167.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_SendTask_1" bpmnElement="SendTask_1" isExpanded="true">
<bpmndi:BPMNShape bpmnElement="SendTask_1" id="BPMNShape_SendTask_1" isExpanded="true">
<dc:Bounds height="50.0" width="110.0" x="448.0" y="149.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_8" labelStyle="BPMNLabelStyle_1">
<dc:Bounds height="14.0" width="67.0" x="469.0" y="167.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_1" bpmnElement="SequenceFlow_1" sourceElement="BPMNShape_1" targetElement="BPMNShape_Task_1">
<di:waypoint xsi:type="dc:Point" x="118.0" y="136.0"/>
<di:waypoint xsi:type="dc:Point" x="118.0" y="174.0"/>
<di:waypoint xsi:type="dc:Point" x="270.0" y="174.0"/>
<bpmndi:BPMNEdge bpmnElement="SequenceFlow_1" id="BPMNEdge_SequenceFlow_1" sourceElement="BPMNShape_1" targetElement="BPMNShape_Task_1">
<bpmndi:BPMNLabel id="BPMNLabel_2">
<dc:Bounds height="28.0" width="62.0" x="145.0" y="175.0"/>
</bpmndi:BPMNLabel>
<di:waypoint x="118.0" y="136.0"/>
<di:waypoint x="118.0" y="174.0"/>
<di:waypoint x="270.0" y="174.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_4" bpmnElement="SequenceFlow_4" sourceElement="BPMNShape_Task_1" targetElement="BPMNShape_SendTask_1">
<di:waypoint xsi:type="dc:Point" x="380.0" y="174.0"/>
<di:waypoint xsi:type="dc:Point" x="414.0" y="174.0"/>
<di:waypoint xsi:type="dc:Point" x="448.0" y="174.0"/>
<bpmndi:BPMNEdge bpmnElement="SequenceFlow_4" id="BPMNEdge_SequenceFlow_4" sourceElement="BPMNShape_Task_1" targetElement="BPMNShape_SendTask_1">
<bpmndi:BPMNLabel id="BPMNLabel_9"/>
<di:waypoint x="380.0" y="174.0"/>
<di:waypoint x="414.0" y="174.0"/>
<di:waypoint x="448.0" y="174.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_5" bpmnElement="SequenceFlow_5" sourceElement="BPMNShape_SendTask_1" targetElement="BPMNShape_2">
<di:waypoint xsi:type="dc:Point" x="558.0" y="174.0"/>
<di:waypoint xsi:type="dc:Point" x="590.0" y="174.0"/>
<di:waypoint xsi:type="dc:Point" x="590.0" y="261.0"/>
<bpmndi:BPMNEdge bpmnElement="SequenceFlow_5" id="BPMNEdge_SequenceFlow_5" sourceElement="BPMNShape_SendTask_1" targetElement="BPMNShape_2">
<bpmndi:BPMNLabel id="BPMNLabel_10"/>
<di:waypoint x="558.0" y="174.0"/>
<di:waypoint x="590.0" y="174.0"/>
<di:waypoint x="590.0" y="261.0"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
<bpmndi:BPMNLabelStyle id="BPMNLabelStyle_1">
<dc:Font name="arial" size="9.0"/>
</bpmndi:BPMNLabelStyle>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>
</bpmn2:definitions>

0 comments on commit bc2b81a

Please sign in to comment.