Skip to content

Transformer ‐ Developer

Kevin Stolz edited this page Jun 24, 2024 · 3 revisions

This section is intended for developers who want to contribute and understand the basic structure and design of the transformer. If you haven't already, check the User section first to understand the supported elements and transformation rules. To set up a new repository and the local development environment, see the other sections in this wiki.

The discussed topics include the BPMN and Petri net models, the test concept, and the actual transformation with pre- and post-processing steps.

Models

To simplify parsing and constructing XML-based diagrams, we use the pydantic_xml XML Objectmapper package. You can find all models here.

The most important models are the BPMN Process and PNML Net classes. These classes define most of the mapped tags and include many helper structures and methods. They make it easier to modify the diagrams efficiently using dictionary lookups, as the object mapper only supports sets or lists.

The default lxml parser is vulnerable to XML attacks. As a secure alternative, we use defusedxml. To enable this, set the environment variable FORCE_STD_XML to any value at startup.

Transformation

For the BPMN to Petri net transformation, the most important function can be found here, and for the Petri net to BPMN transformation here.

The transformation can be simplified into the following steps:

  1. Apply preprocessing to the source diagram.
  2. Move workflow-related elements from the source diagram to temporary storage.
  3. Use the mapping rules to add the remaining elements to the target diagram.
  4. Use the mapping rules to add the previously moved workflow elements to the target diagram.
  5. Add the edges to the target diagram.
  6. Apply postprocessing to the target diagram.

Although these steps may seem overcomplicated at first—since preprocessing could be handled directly while creating the target diagram without modifying the source diagram—this approach improves readability and maintainability. Therefore, a potentially less efficient but more understandable approach was chosen.

Preprocessing

BPMN to Workflow Net

To handle OR-gates, we replace them with a combination of XOR and AND operators. This involves finding the last flow that joins each opened flow from the OR-split. This heuristic might fail with very complex diagrams.

Additionally, we remove unnecessary gateways that do not split the control flow. We place a temporary GenericBPMNNode between adjacent gateways.

Adjacent BPMN elements that transform into transitions can break the process if next to other workflow elements. To prevent this, we insert helper nodes around each critical element. These will transform into Places.

Workflow Net to BPMN

In Petri nets, dangling transitions have no incoming or outgoing arcs and can produce unlimited tokens, a feature not present in BPMN. We add a place before each dangling transition.

Workflow operators can combine every possible combination of joins and splits for AND- and XOR-Gateways. However, combined XOR-AND and AND-XOR combinations are not supported in BPMN. We split these into multiple gateways. We also replace workflow operators with a single helper node, reducing multiple transitions and places to simplify the transformation.

Transitions with multiple incoming or outgoing arcs are joins. If they have a name, they are also implicit tasks. BPMN does not support this concept. We split the implicit task and gateway into multiple elements.

Event triggers are part of transitions or operators but must be separate elements in BPMN. We split them into multiple elements. For simple transition tasks and splits, we prepend the trigger helper node. For joins, we append it. For Join/Split Combinations, we split the operator into a join and a split, inserting the trigger helper node between them.

Postprocessing

BPMN to Workflow Net

In workflow nets, triggers can be assigned to transitions or operators but are always a single element. After transformation, the trigger transition merges with the following transition or workflow operator combination. This works only if the following transition has one incoming arc from the place after the trigger.

Workflow Net to BPMN

Petri nets cannot have a place following another place or a transition following another transition. Therefore, we introduce silent transitions. Although these are removed during the transformation, they are transformed into gates/empty tasks as part of the user guide. During postprocessing, we remove empty tasks and XOR-gates with exactly one incoming and outgoing flow.

Test Concept

The most important tests are located here. These tests isolate all mapping rules to facilitate easier debugging when specific elements are wrongly transformed.

The actual test cases are defined here.

For each element or similar element groups like gateways, there is a function that creates the source and expected diagram as Diagram as Code.

def start_end():
    case = "start_end"
    se_id = "start"
    ee_id = "end"
    bpmn = create_bpmn(case, [[StartEvent(id=se_id), EndEvent(id=ee_id)]])
    net = create_petri_net(
        case,
        [
            [
                Place(id=se_id),
                Transition(id=create_silent_node_name(se_id, ee_id)),
                Place(id=ee_id),
            ]
        ],
    )
    return bpmn, net, case 

The above example shows one of the simplest cases to check if the BPMN with only a start and end event is transformed properly. The Petri net that is generated in the test cases will then be compared to the defined net.

To test diagrams for equality, the methods in this folder are used. Because string equality has potential limitations for comparing XML-based diagrams, each element is transformed into a string with only specific attributes to compare the diagrams for equality.