Skip to content

Commit

Permalink
improve BPMNFlowIterator
Browse files Browse the repository at this point in the history
issue #237
  • Loading branch information
rsoika committed Aug 17, 2024
1 parent 4a0bd9c commit 4863f1c
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public Event addBoundaryEvent(String eventID, String name) throws BPMNModelExcep
}

/**
* This method returns a list of all boundaray Events attached to this activity.
* This method returns a list of all boundary Events attached to this activity.
*
* @return
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
/**
* The BPMNFlowIterator can be used to iterate through a BPMN model. Based on
* a Source BPMNElement the class routes to the next Flow Element fulfilling
* a
* given criteria. For example you can find all Event Nodes followed by an
* a given criteria. For example you can find all Event Nodes followed by an
* Activity Node. Or you can navigate to the next Activity from an Event.
* <p>
* The BPMNFlowIterator expects a filter argument (Functional Interface
* Predicate) with one BPMNElementNode argument that return a boolean value.
* <p>
* In case the filter does not specify a Gateway, Gateway Nodes are ignored.
* In case the filter does not match the current element, the Iterator will
* recursive follow the sequence flow until the next matching element was found.
*
*/
public class BPMNFlowIterator<T> implements Iterator<BPMNElementNode> {
Expand Down Expand Up @@ -93,9 +93,8 @@ public BPMNElementNode next() {
* Iterates tough all outgoing sequence flows and tests if the target element
* matches the filter criteria.
* <p>
* If a element does not match the filter criteria and is an instance of a
* Gateway, the method will recursive call all following elements of the gateway
* node.
* If an element does not match the filter criteria the method will recursive
* call itself and follow the further sequence flow.
*
* @param currentNode
*/
Expand All @@ -112,12 +111,9 @@ private void findValidNodes(BPMNElementNode currentNode) {
if (filter.test(node)) {
targetNodes.add(node);
} else {
// if the node is a Gateway, recursively search its outgoing flows
if (node instanceof Gateway) {
findValidNodes(node);
}
// if the node does not match the filter go ahead by a recursive call....
findValidNodes(node);
}

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -67,22 +69,29 @@ public void testFindStartTask1WithEvents() throws BPMNModelException {
BPMNModel model = BPMNModelFactory.read("/refmodel-navigation-02.bpmn");
BPMNProcess process = model.openDefaultProces();

// get start Task1
// find all End Task Elements
BPMNEndElementIterator endElements = new BPMNEndElementIterator<>(process, n -> n instanceof Activity);
assertNotNull(endElements);
assertTrue(endElements.hasNext());

BPMNElementNode task = endElements.next();
List<BPMNElementNode> allNodes = new ArrayList<>();
while (endElements.hasNext()) {
allNodes.add(endElements.next());
}
// Sort by name
allNodes.sort((element1, element2) -> element1.getName().compareTo(element2.getName()));

// We expect 2 elements
assertEquals(2, allNodes.size());
BPMNElementNode task = allNodes.get(0);
assertNotNull(task);
assertEquals("Task-3", task.getName());
assertEquals("Task-2", task.getName());

// next should be task-2
task = endElements.next();
task = allNodes.get(1);
assertNotNull(task);
assertEquals("Task-2", task.getName());
assertEquals("Task-3", task.getName());

// no more elements expected
assertFalse(endElements.hasNext());
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.openbpmn.metamodel.navigation;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

Expand Down Expand Up @@ -119,22 +120,20 @@ public void testFindTargetFromEvent1() throws BPMNModelException {
BPMNProcess process = model.openDefaultProces();

// get Event2
BPMNElementNode event1 = process.findElementNodeById("event_TGi3FA");
assertNotNull(event1);
BPMNElementNode eventForwardAndSubmit = process.findElementNodeById("event_forwardAndSubmit");
assertNotNull(eventForwardAndSubmit);

BPMNFlowIterator<Event> taskNavigator = new BPMNFlowIterator<Event>(event1,
// Find the target Task... (task-2)
BPMNFlowIterator<Event> taskNavigator = new BPMNFlowIterator<Event>(eventForwardAndSubmit,
n -> n instanceof Activity);
assertNotNull(taskNavigator);

// we expect 3 Event Nodes

List<String> elementNames = new ArrayList();
while (taskNavigator.hasNext()) {
Activity task = (Activity) taskNavigator.next();
elementNames.add(task.getName());
}

assertEquals(0, elementNames.size());
assertTrue(taskNavigator.hasNext());
BPMNElementNode targetTask = taskNavigator.next();
assertEquals("Task-2", targetTask.getName());
// note more task exprected
assertFalse(taskNavigator.hasNext());

}

Expand Down
141 changes: 78 additions & 63 deletions open-bpmn.metamodel/src/test/resources/refmodel-navigation-01.bpmn
Original file line number Diff line number Diff line change
@@ -1,153 +1,168 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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:open-bpmn="http://open-bpmn.org/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exporter="org.openbpmn" exporterVersion="1.0.0" targetNamespace="http://org.openbpmn">
<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:open-bpmn="http://open-bpmn.org/XMLSchema"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exporter="org.openbpmn" exporterVersion="1.0.0" targetNamespace="http://org.openbpmn">
<bpmn2:extensionElements>
<open-bpmn:auto-align>true</open-bpmn:auto-align>
</bpmn2:extensionElements>
<bpmn2:process id="process_1" name="Default Process" processType="Public">
<bpmn2:documentation id="documentation_cSzSmg"/>
<bpmn2:documentation id="documentation_cSzSmg" />
<bpmn2:startEvent id="event_3l2H6A" name="Start">
<bpmn2:documentation id="documentation_LFBrTA"/>
<bpmn2:documentation id="documentation_LFBrTA" />
<bpmn2:outgoing>sequenceFlow_GxGAgQ</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:task id="task_SBK01w" name="Task-1">
<bpmn2:documentation id="documentation_s0UvSQ"/>
<bpmn2:documentation id="documentation_s0UvSQ" />
<bpmn2:incoming>sequenceFlow_GxGAgQ</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_GMnxSA</bpmn2:outgoing>
<bpmn2:outgoing>sequenceFlow_f4hhBA</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:task id="task_1gbByA" name="Task-2">
<bpmn2:documentation id="documentation_ceiluQ"/>
<bpmn2:documentation id="documentation_ceiluQ" />
<bpmn2:incoming>sequenceFlow_NVfK3w</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_MNZU9g</bpmn2:outgoing>
<bpmn2:incoming>sequenceFlow_Y0i62A</bpmn2:incoming>
<bpmn2:incoming>sequenceFlow_gZSk0Q</bpmn2:incoming>
</bpmn2:task>
<bpmn2:intermediateCatchEvent id="event_IyD2LA" name="Submit">
<bpmn2:documentation id="documentation_33D0jg"/>
<bpmn2:documentation id="documentation_33D0jg" />
<bpmn2:incoming>sequenceFlow_GMnxSA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_gZSk0Q</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_cFt0jw" name="Update">
<bpmn2:documentation id="documentation_IYAQ3A"/>
<bpmn2:documentation id="documentation_IYAQ3A" />
<bpmn2:outgoing>sequenceFlow_NVfK3w</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_GxGAgQ" sourceRef="event_3l2H6A" targetRef="task_SBK01w">
<bpmn2:documentation id="documentation_20Np5A"/>
<bpmn2:documentation id="documentation_20Np5A" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_GMnxSA" sourceRef="task_SBK01w" targetRef="event_IyD2LA">
<bpmn2:documentation id="documentation_h8VJzg"/>
<bpmn2:documentation id="documentation_h8VJzg" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_gZSk0Q" sourceRef="event_IyD2LA" targetRef="task_1gbByA">
<bpmn2:documentation id="documentation_062kWA"/>
<bpmn2:documentation id="documentation_062kWA" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_NVfK3w" sourceRef="event_cFt0jw" targetRef="task_1gbByA">
<bpmn2:documentation id="documentation_Musc0Q"/>
<bpmn2:documentation id="documentation_Musc0Q" />
</bpmn2:sequenceFlow>
<bpmn2:endEvent id="event_1hnRCg" name="End">
<bpmn2:documentation id="documentation_oWFPtg"/>
<bpmn2:documentation id="documentation_oWFPtg" />
<bpmn2:incoming>sequenceFlow_MNZU9g</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:sequenceFlow id="sequenceFlow_MNZU9g" sourceRef="task_1gbByA" targetRef="event_1hnRCg">
<bpmn2:documentation id="documentation_oCoP2g"/>
<bpmn2:documentation id="documentation_oCoP2g" />
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="event_TGi3FA" name="Forward and submit">
<bpmn2:documentation id="documentation_ZnTTAg"/>
<bpmn2:intermediateCatchEvent id="event_forwardAndSubmit" name="Forward and submit">
<bpmn2:documentation id="documentation_ZnTTAg" />
<bpmn2:incoming>sequenceFlow_f4hhBA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_j9TRfA</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_K0tY3Q" name="Update">
<bpmn2:documentation id="documentation_AEWfpA"/>
<bpmn2:documentation id="documentation_AEWfpA" />
<bpmn2:incoming>sequenceFlow_j9TRfA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_Y0i62A</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_f4hhBA" sourceRef="task_SBK01w" targetRef="event_TGi3FA">
<bpmn2:documentation id="documentation_Vx6BCQ"/>
<bpmn2:sequenceFlow id="sequenceFlow_f4hhBA" sourceRef="task_SBK01w"
targetRef="event_forwardAndSubmit">
<bpmn2:documentation id="documentation_Vx6BCQ" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_j9TRfA" sourceRef="event_TGi3FA" targetRef="event_K0tY3Q">
<bpmn2:documentation id="documentation_tXhljQ"/>
<bpmn2:sequenceFlow id="sequenceFlow_j9TRfA" sourceRef="event_forwardAndSubmit"
targetRef="event_K0tY3Q">
<bpmn2:documentation id="documentation_tXhljQ" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_Y0i62A" sourceRef="event_K0tY3Q" targetRef="task_1gbByA">
<bpmn2:documentation id="documentation_0kaOpw"/>
<bpmn2:documentation id="documentation_0kaOpw" />
</bpmn2:sequenceFlow>
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1" name="OpenBPMN Diagram">
<bpmndi:BPMNPlane bpmnElement="process_1" id="BPMNPlane_1">
<bpmndi:BPMNShape bpmnElement="event_3l2H6A" id="BPMNShape_0aH0xQ">
<dc:Bounds height="36.0" width="36.0" x="137.0" y="107.0"/>
<dc:Bounds height="36.0" width="36.0" x="137.0" y="107.0" />
<bpmndi:BPMNLabel id="BPMNLabel_qMH7eA">
<dc:Bounds height="20.0" width="100.0" x="103.0" y="146.0"/>
<dc:Bounds height="20.0" width="100.0" x="103.0" y="146.0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_SBK01w" id="BPMNShape_Q2EOdA">
<dc:Bounds height="50.0" width="110.0" x="220.0" y="100.0"/>
<dc:Bounds height="50.0" width="110.0" x="220.0" y="100.0" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_1gbByA" id="BPMNShape_GMm6WQ">
<dc:Bounds height="50.0" width="110.0" x="630.0" y="100.0"/>
<dc:Bounds height="50.0" width="110.0" x="630.0" y="100.0" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_IyD2LA" id="BPMNShape_3v50hg">
<dc:Bounds height="36.0" width="36.0" x="387.0" y="107.0"/>
<dc:Bounds height="36.0" width="36.0" x="387.0" y="107.0" />
<bpmndi:BPMNLabel id="BPMNLabel_tGbTCQ">
<dc:Bounds height="20.0" width="100.0" x="361.0" y="146.0"/>
<dc:Bounds height="20.0" width="100.0" x="361.0" y="146.0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_cFt0jw" id="BPMNShape_svU3dA">
<dc:Bounds height="36.0" width="36.0" x="667.0" y="177.0"/>
<dc:Bounds height="36.0" width="36.0" x="667.0" y="177.0" />
<bpmndi:BPMNLabel id="BPMNLabel_rQDOmA">
<dc:Bounds height="20.0" width="100.0" x="635.0" y="221.0"/>
<dc:Bounds height="20.0" width="100.0" x="635.0" y="221.0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_GxGAgQ" id="BPMNEdge_N7M68g" sourceElement="BPMNShape_0aH0xQ" targetElement="BPMNShape_Q2EOdA">
<di:waypoint x="173.0" y="125.0"/>
<di:waypoint x="220.0" y="125.0"/>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_GxGAgQ" id="BPMNEdge_N7M68g"
sourceElement="BPMNShape_0aH0xQ" targetElement="BPMNShape_Q2EOdA">
<di:waypoint x="173.0" y="125.0" />
<di:waypoint x="220.0" y="125.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_GMnxSA" id="BPMNEdge_YrvARw" sourceElement="BPMNShape_Q2EOdA" targetElement="BPMNShape_3v50hg">
<di:waypoint x="330.0" y="125.0"/>
<di:waypoint x="331.0" y="125.0"/>
<di:waypoint x="387.0" y="125.0"/>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_GMnxSA" id="BPMNEdge_YrvARw"
sourceElement="BPMNShape_Q2EOdA" targetElement="BPMNShape_3v50hg">
<di:waypoint x="330.0" y="125.0" />
<di:waypoint x="331.0" y="125.0" />
<di:waypoint x="387.0" y="125.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_gZSk0Q" id="BPMNEdge_qtWF7Q" sourceElement="BPMNShape_3v50hg" targetElement="BPMNShape_GMm6WQ">
<di:waypoint x="423.0" y="125.0"/>
<di:waypoint x="630.0" y="125.0"/>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_gZSk0Q" id="BPMNEdge_qtWF7Q"
sourceElement="BPMNShape_3v50hg" targetElement="BPMNShape_GMm6WQ">
<di:waypoint x="423.0" y="125.0" />
<di:waypoint x="630.0" y="125.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_NVfK3w" id="BPMNEdge_bEih0A" sourceElement="BPMNShape_svU3dA" targetElement="BPMNShape_GMm6WQ">
<di:waypoint x="685.0" y="177.0"/>
<di:waypoint x="685.0" y="150.0"/>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_NVfK3w" id="BPMNEdge_bEih0A"
sourceElement="BPMNShape_svU3dA" targetElement="BPMNShape_GMm6WQ">
<di:waypoint x="685.0" y="177.0" />
<di:waypoint x="685.0" y="150.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape bpmnElement="event_1hnRCg" id="BPMNShape_J37zoA">
<dc:Bounds height="36.0" width="36.0" x="777.0" y="107.0"/>
<dc:Bounds height="36.0" width="36.0" x="777.0" y="107.0" />
<bpmndi:BPMNLabel id="BPMNLabel_eLca0w">
<dc:Bounds height="20.0" width="100.0" x="751.0" y="146.0"/>
<dc:Bounds height="20.0" width="100.0" x="751.0" y="146.0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_MNZU9g" id="BPMNEdge_E2gROQ" sourceElement="BPMNShape_GMm6WQ" targetElement="BPMNShape_J37zoA">
<di:waypoint x="740.0" y="125.0"/>
<di:waypoint x="777.0" y="125.0"/>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_MNZU9g" id="BPMNEdge_E2gROQ"
sourceElement="BPMNShape_GMm6WQ" targetElement="BPMNShape_J37zoA">
<di:waypoint x="740.0" y="125.0" />
<di:waypoint x="777.0" y="125.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape bpmnElement="event_TGi3FA" id="BPMNShape_7yirEQ">
<dc:Bounds height="36.0" width="36.0" x="257.0" y="-23.0"/>
<bpmndi:BPMNShape bpmnElement="event_forwardAndSubmit" id="BPMNShape_7yirEQ">
<dc:Bounds height="36.0" width="36.0" x="257.0" y="-23.0" />
<bpmndi:BPMNLabel id="BPMNLabel_5N0BqA">
<dc:Bounds height="20.0" width="100.0" x="226.0" y="21.0"/>
<dc:Bounds height="20.0" width="100.0" x="226.0" y="21.0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_K0tY3Q" id="BPMNShape_BapvzQ">
<dc:Bounds height="36.0" width="36.0" x="387.0" y="-23.0"/>
<dc:Bounds height="36.0" width="36.0" x="387.0" y="-23.0" />
<bpmndi:BPMNLabel id="BPMNLabel_NVdCQA">
<dc:Bounds height="20.0" width="100.0" x="357.0" y="17.0"/>
<dc:Bounds height="20.0" width="100.0" x="357.0" y="17.0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_f4hhBA" id="BPMNEdge_80SHFQ" sourceElement="BPMNShape_Q2EOdA" targetElement="BPMNShape_7yirEQ">
<di:waypoint x="275.0" y="100.0"/>
<di:waypoint x="275.0" y="13.0"/>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_f4hhBA" id="BPMNEdge_80SHFQ"
sourceElement="BPMNShape_Q2EOdA" targetElement="BPMNShape_7yirEQ">
<di:waypoint x="275.0" y="100.0" />
<di:waypoint x="275.0" y="13.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_j9TRfA" id="BPMNEdge_f008gw" sourceElement="BPMNShape_7yirEQ" targetElement="BPMNShape_BapvzQ">
<di:waypoint x="293.0" y="-5.0"/>
<di:waypoint x="387.0" y="-5.0"/>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_j9TRfA" id="BPMNEdge_f008gw"
sourceElement="BPMNShape_7yirEQ" targetElement="BPMNShape_BapvzQ">
<di:waypoint x="293.0" y="-5.0" />
<di:waypoint x="387.0" y="-5.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_Y0i62A" id="BPMNEdge_KOnSEA" sourceElement="BPMNShape_BapvzQ" targetElement="BPMNShape_GMm6WQ">
<di:waypoint x="423.0" y="-5.0"/>
<di:waypoint x="685.0" y="-5.0"/>
<di:waypoint x="685.0" y="100.0"/>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_Y0i62A" id="BPMNEdge_KOnSEA"
sourceElement="BPMNShape_BapvzQ" targetElement="BPMNShape_GMm6WQ">
<di:waypoint x="423.0" y="-5.0" />
<di:waypoint x="685.0" y="-5.0" />
<di:waypoint x="685.0" y="100.0" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>
</bpmn2:definitions>

0 comments on commit 4863f1c

Please sign in to comment.