Skip to content

Commit

Permalink
added EndElementIterator and BPMNLinkNavigator
Browse files Browse the repository at this point in the history
Issue #237
  • Loading branch information
rsoika committed Aug 11, 2024
1 parent 355dbd3 commit 1229bc7
Show file tree
Hide file tree
Showing 4 changed files with 233 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package org.openbpmn.bpmn.navigation;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.logging.Logger;

import org.openbpmn.bpmn.BPMNTypes;
import org.openbpmn.bpmn.elements.BPMNProcess;
import org.openbpmn.bpmn.elements.Event;
import org.openbpmn.bpmn.elements.SequenceFlow;
import org.openbpmn.bpmn.elements.core.BPMNElementNode;
import org.openbpmn.bpmn.exceptions.BPMNValidationException;

/**
* The BPMNEndElementIterator returns Elements that are immediately followed by
* a end event. This can be either an Intermediate Catch/Throw Events or an
* Activity (Task).
* <p>
* With the filter argument (Functional Interface Predicate) an argument can be
* provided to return only specific elements.
*
*/
public class BPMNEndElementIterator<T> implements Iterator<BPMNElementNode> {

protected static Logger logger = Logger.getLogger(BPMNElementNode.class.getName());
Set<Event> _endEventNodes;

private List<BPMNElementNode> resultElementList;
private Iterator<BPMNElementNode> allEndElementsIterator;

/**
* Creates an Iterator with a given filter criteria.
* The method collects all BPMNElements following the given start element and
* matching the given filter
*
* @param bpmnElementNode
* @param filter
* @throws BPMNValidationException
*/
public BPMNEndElementIterator(BPMNProcess process, Predicate<BPMNElementNode> filter) {
resultElementList = new ArrayList<>();

// First find all Start Events in the model
_endEventNodes = new HashSet<>();
Set<Event> allEventNodes = process.getEvents();
for (Event _event : allEventNodes) {
if (BPMNTypes.END_EVENT.equals(_event.getType())) {
_endEventNodes.add(_event);
}
}

// next resolve all immediate predecessors.
for (BPMNElementNode element : _endEventNodes) {
Set<SequenceFlow> incomingFlows = element.getIngoingSequenceFlows();
for (SequenceFlow _flow : incomingFlows) {
BPMNElementNode sourceNode = _flow.getSourceElement();
if (filter.test(sourceNode)) {
resultElementList.add(sourceNode);
}
}
}
// create a local iterator instance
allEndElementsIterator = resultElementList.iterator();
}

@Override
public boolean hasNext() {
return allEndElementsIterator.hasNext();
}

@Override
public BPMNElementNode next() {
return allEndElementsIterator.next();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.openbpmn.bpmn.navigation;

import java.util.Set;

import org.openbpmn.bpmn.BPMNTypes;
import org.openbpmn.bpmn.elements.Event;
import org.openbpmn.bpmn.elements.core.BPMNElementNode;

/**
* The BPMNLinkNavigator navigates from a Link Throw Event to a Link Catch event
*
*
*/
public class BPMNLinkNavigator {

public BPMNElementNode findNext(BPMNElementNode node) {

// is it a throw event?
if (BPMNTypes.THROW_EVENT.equals(node.getType())) {
String linkName = node.getName();
// now find the corresponding first catch event with the same name
Set<? extends BPMNElementNode> filteredElementList = node.getBpmnProcess()
.findElementNodes(
n -> (BPMNTypes.CATCH_EVENT.equals(n.getType()) //
&& ((Event) n).getEventDefinitionsByType(BPMNTypes.EVENT_DEFINITION_LINK)
.size() > 0 //
&& linkName.equals(n.getName())));

// return the first one...
if (filteredElementList != null && filteredElementList.size() > 0) {
return filteredElementList.iterator().next();
}

}

// no match
return null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
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;

import java.util.logging.Logger;

import org.junit.jupiter.api.Test;
import org.openbpmn.bpmn.BPMNModel;
import org.openbpmn.bpmn.elements.Activity;
import org.openbpmn.bpmn.elements.BPMNProcess;
import org.openbpmn.bpmn.elements.core.BPMNElementNode;
import org.openbpmn.bpmn.exceptions.BPMNModelException;
import org.openbpmn.bpmn.navigation.BPMNEndElementIterator;
import org.openbpmn.bpmn.util.BPMNModelFactory;
import org.openbpmn.metamodel.examples.TestCreateEdges;

/**
* Test class to test the EndNavigator.
*
*/
public class TestEndNavigation {
private static Logger logger = Logger.getLogger(TestCreateEdges.class.getName());

/**
* This test loads model 'refmodel-navigation-01.bpmn' and finds the start
* task-1.
*
* @throws BPMNModelException
*
*/
@SuppressWarnings("rawtypes")
@Test
public void testFindEndTask1() throws BPMNModelException {

logger.info("...read model");
BPMNModel model = BPMNModelFactory.read("/refmodel-navigation-01.bpmn");
BPMNProcess process = model.openDefaultProces();

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

BPMNElementNode task2 = endElements.next();
assertNotNull(task2);

assertEquals("Task-2", task2.getName());
// no more elements expected
assertFalse(endElements.hasNext());
}

/**
* This test loads model 'refmodel-navigation-02.bpmn' and finds 2 End Elements
* (Task-2 and Task-3)
*
* @throws BPMNModelException
*
*/
@SuppressWarnings("rawtypes")
@Test
public void testFindStartTask1WithEvents() throws BPMNModelException {

logger.info("...read model");
BPMNModel model = BPMNModelFactory.read("/refmodel-navigation-02.bpmn");
BPMNProcess process = model.openDefaultProces();

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

BPMNElementNode task = endElements.next();
assertNotNull(task);
assertEquals("Task-3", task.getName());

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

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

}
33 changes: 25 additions & 8 deletions open-bpmn.metamodel/src/test/resources/refmodel-navigation-02.bpmn
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
</bpmn2:task>
<bpmn2:task id="task_1gbByA" name="Task-2">
<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>
Expand All @@ -37,12 +36,13 @@
<bpmn2:sequenceFlow id="sequenceFlow_gZSk0Q" sourceRef="event_IyD2LA" targetRef="task_1gbByA">
<bpmn2:documentation id="documentation_062kWA"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_NVfK3w" sourceRef="event_cFt0jw" targetRef="task_1gbByA">
<bpmn2:sequenceFlow id="sequenceFlow_NVfK3w" sourceRef="event_cFt0jw" targetRef="task_EUj8dg">
<bpmn2:documentation id="documentation_Musc0Q"/>
</bpmn2:sequenceFlow>
<bpmn2:endEvent id="event_1hnRCg" name="End">
<bpmn2:documentation id="documentation_oWFPtg"/>
<bpmn2:incoming>sequenceFlow_MNZU9g</bpmn2:incoming>
<bpmn2:incoming>sequenceFlow_GLS2PA</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:sequenceFlow id="sequenceFlow_MNZU9g" sourceRef="task_1gbByA" targetRef="event_1hnRCg">
<bpmn2:documentation id="documentation_oCoP2g"/>
Expand Down Expand Up @@ -86,6 +86,15 @@
<bpmn2:text id="text_wEMK9Q"><![CDATA[Test Model with a Gateway but without conditions ]]></bpmn2:text>
<bpmn2:documentation id="documentation_b0SWvQ"/>
</bpmn2:textAnnotation>
<bpmn2:task id="task_EUj8dg" name="Task-3">
<bpmn2:documentation id="documentation_TlAEFw"/>
<bpmn2:incoming>sequenceFlow_Y0i62A</bpmn2:incoming>
<bpmn2:incoming>sequenceFlow_NVfK3w</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_GLS2PA</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:sequenceFlow id="sequenceFlow_GLS2PA" sourceRef="task_EUj8dg" targetRef="event_1hnRCg">
<bpmn2:documentation id="documentation_QwooKw"/>
</bpmn2:sequenceFlow>
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1" name="OpenBPMN Diagram">
<bpmndi:BPMNPlane bpmnElement="process_1" id="BPMNPlane_1">
Expand All @@ -108,9 +117,9 @@
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_cFt0jw" id="BPMNShape_svU3dA">
<dc:Bounds height="36.0" width="36.0" x="667.0" y="227.0"/>
<dc:Bounds height="36.0" width="36.0" x="527.0" y="227.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_rQDOmA">
<dc:Bounds height="20.0" width="100.0" x="635.0" y="271.0"/>
<dc:Bounds height="20.0" width="100.0" x="495.0" y="271.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_GxGAgQ" id="BPMNEdge_N7M68g" sourceElement="BPMNShape_0aH0xQ" targetElement="BPMNShape_Q2EOdA">
Expand All @@ -121,9 +130,9 @@
<di:waypoint x="563.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="227.0"/>
<di:waypoint x="685.0" y="150.0"/>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_NVfK3w" id="BPMNEdge_bEih0A" sourceElement="BPMNShape_svU3dA" targetElement="BPMNShape_mrhRYw">
<di:waypoint x="563.0" y="245.0"/>
<di:waypoint x="630.0" y="245.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"/>
Expand Down Expand Up @@ -176,11 +185,19 @@
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_NPmh3w" id="BPMNEdge_8EldUw" sourceElement="BPMNShape_7yirEQ" targetElement="BPMNShape_svU3dA">
<di:waypoint x="423.0" y="245.0"/>
<di:waypoint x="667.0" y="245.0"/>
<di:waypoint x="527.0" y="245.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape bpmnElement="textAnnotation_vNlcXQ" id="BPMNShape_EKHmHg">
<dc:Bounds height="89.0" width="247.0" x="70.0" y="-60.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_EUj8dg" id="BPMNShape_mrhRYw">
<dc:Bounds height="50.0" width="110.0" x="630.0" y="220.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_GLS2PA" id="BPMNEdge_kwoxtA" sourceElement="BPMNShape_mrhRYw" targetElement="BPMNShape_J37zoA">
<di:waypoint x="740.0" y="245.0"/>
<di:waypoint x="796.0" y="245.0"/>
<di:waypoint x="796.0" y="142.97220075561142"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>

0 comments on commit 1229bc7

Please sign in to comment.