-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
documented diagram converter core (#1029)
* documented diagram converter core * disable unstable test
- Loading branch information
1 parent
4eb6ddd
commit 3a17ec5
Showing
10 changed files
with
356 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
# Diagram Converter Core | ||
|
||
This is the core module of the diagram converter, containing the `BpmnConverter` plus its factory, the `BpmnConverterFactory`. | ||
|
||
## How does it work? | ||
|
||
Works in 2 phases: | ||
|
||
* exploring the BPMN XML | ||
* this is done in a visitor pattern, the interface to use is `DomElementVisitor` | ||
* each element gets visited | ||
* convertibles are created for each process element | ||
* they can be decorated with aspects for the conversion | ||
* the conversion is executed | ||
* decorated convertibles are processed | ||
* the registered aspects are adjusted in the BPMN XML | ||
* this is done in another visitor pattern, the interface to use is `Conversion` | ||
* the diagram becomes a Camunda 8 diagram | ||
|
||
## How can I use it? | ||
|
||
You can bootstrap the `BpmnConverter` in an easy way: | ||
|
||
```java | ||
|
||
BpmnConverter converter = BpmnConverterFactory.getInstance().get(); | ||
``` | ||
|
||
This will return a converter that is bootstrapped using SPI for `DomElementVisitor`, `Conversion` and `NotificationService`. | ||
|
||
If you want to build a custom converter, you can add to the SPI resources. | ||
|
||
If this is not sufficient, you can bootstrap the converter in a custom way: | ||
|
||
```java | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
List<DomElementVisitor> visitors = loadDomElementVisitors(); | ||
List<Conversion> conversions = loadConversions(); | ||
NotificationService notificationService = laodNotificationService(); | ||
|
||
BpmnConverter converter = new BpmnConverter(visitors, conversions, notificationService); | ||
``` | ||
|
||
Next, you need `ConverterProperties`. They control the way the converter will handle several aspects of the conversion. | ||
|
||
You can bootstrap the properties in an easy way: | ||
|
||
```java | ||
|
||
ConverterProperties properties = ConverterPropertiesFactory.getInstance().get(); | ||
``` | ||
|
||
You can also customize the used converter properties: | ||
|
||
```java | ||
|
||
DefaultConverterProperties defaultConverterProperties = new DefaultConverterProperties(); | ||
// I want to migrate to an older platform version | ||
defaultConverterProperties.setPlatformVersion("8.5"); | ||
|
||
ConverterProperties properties = ConverterPropertiesFactory | ||
.getInstance() | ||
.merge(defaultConverterProperties); | ||
``` | ||
|
||
Now, you are able to convert process models or just receive a check result: | ||
|
||
```java | ||
|
||
BpmnConverter converter = BpmnConverterFactory | ||
.getInstance() | ||
.get(); | ||
// this comes from the camunda 7 bpmn model package | ||
BpmnModelInstance modelInstance = loadModel(); | ||
ConverterProperties properties = ConverterPropertiesFactory.getInstance().get(); | ||
|
||
// the results will be in the provided modelInstance | ||
converter.convert(modelInstance, properties); | ||
|
||
// the results are returned, the model instance is also modified | ||
|
||
BpmnDiagramCheckResult result = converter.check(modelInstance, properties); | ||
``` | ||
|
||
## How can I extend it? | ||
|
||
Beside the way of using custom bootstrapping mechanisms, the easiest way to extend is by using the capabilities of the underlying SPI. | ||
|
||
You can find an example in the `/example` section of the root project. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<artifactId>extended-converter</artifactId> | ||
<packaging>jar</packaging> | ||
|
||
<parent> | ||
<groupId>org.camunda.community.migration</groupId> | ||
<artifactId>migration-examples-parent</artifactId> | ||
<version>1.0.0-SNAPSHOT</version> | ||
</parent> | ||
|
||
<properties> | ||
<encoding>UTF-8</encoding> | ||
<project.build.sourceEncoding>${encoding}</project.build.sourceEncoding> | ||
<project.build.resourceEncoding>${encoding}</project.build.resourceEncoding> | ||
<version.java>17</version.java> | ||
<maven.compiler.source>${version.java}</maven.compiler.source> | ||
<maven.compiler.target>${version.java}</maven.compiler.target> | ||
<version.camunda-7-to-8-migration>0.10.0</version.camunda-7-to-8-migration> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.camunda.community.migration</groupId> | ||
<artifactId>backend-diagram-converter-core</artifactId> | ||
<version>${version.camunda-7-to-8-migration}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.junit.jupiter</groupId> | ||
<artifactId>junit-jupiter</artifactId> | ||
<version>5.11.0</version> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.assertj</groupId> | ||
<artifactId>assertj-core</artifactId> | ||
<scope>test</scope> | ||
<version>3.26.3</version> | ||
</dependency> | ||
</dependencies> | ||
|
||
</project> |
81 changes: 81 additions & 0 deletions
81
...va/org/camunda/community/migration/example/extendedConverter/CustomDomElementVisitor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package org.camunda.community.migration.example.extendedConverter; | ||
|
||
import org.camunda.bpm.model.xml.instance.DomElement; | ||
import org.camunda.community.migration.converter.BpmnDiagramCheckResult.Severity; | ||
import org.camunda.community.migration.converter.DomElementVisitorContext; | ||
import org.camunda.community.migration.converter.convertible.ExclusiveGatewayConvertible; | ||
import org.camunda.community.migration.converter.message.ComposedMessage; | ||
import org.camunda.community.migration.converter.visitor.DomElementVisitor; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.stream.Collectors; | ||
|
||
import static org.camunda.community.migration.converter.NamespaceUri.*; | ||
|
||
public class CustomDomElementVisitor implements DomElementVisitor { | ||
private static final Logger LOG = LoggerFactory.getLogger(CustomDomElementVisitor.class); | ||
|
||
@Override | ||
public void visit(DomElementVisitorContext context) { | ||
DomElement element = context.getElement(); | ||
if (element | ||
.getNamespaceURI() | ||
.equals(BPMN) && element | ||
.getLocalName() | ||
.equals("exclusiveGateway")) { | ||
// this is only applied to exclusive gateways | ||
List<String> outgoingSequenceFlowIds = findOutgoingSequenceFlows(element); | ||
if (outgoingSequenceFlowIds.size() > 1) { | ||
// only when they are forking | ||
List<ConditionExpression> expressions = outgoingSequenceFlowIds | ||
.stream() | ||
.map(id -> element | ||
.getDocument() | ||
.getElementById(id)) | ||
.filter(Objects::nonNull) | ||
.map(this::extractConditionExpression) | ||
.filter(Objects::nonNull) | ||
.toList(); | ||
String property = expressions | ||
.stream() | ||
.map(e -> e.id() + ": " + e.language() + ": " + e.expression()) | ||
.collect(Collectors.joining(", ")); | ||
context.addConversion(ExclusiveGatewayConvertible.class, | ||
gateway -> gateway.addZeebeProperty("originalExpressions", property) | ||
); | ||
ComposedMessage composedMessage = new ComposedMessage(); | ||
composedMessage.setMessage("Original expressions are: " + property); | ||
composedMessage.setSeverity(Severity.INFO); | ||
context.addMessage(composedMessage); | ||
} | ||
} | ||
} | ||
|
||
private List<String> findOutgoingSequenceFlows(DomElement element) { | ||
return element | ||
.getChildElementsByNameNs(BPMN, "outgoing") | ||
.stream() | ||
.map(DomElement::getTextContent) | ||
.toList(); | ||
} | ||
|
||
private ConditionExpression extractConditionExpression(DomElement sequenceFlow) { | ||
return sequenceFlow | ||
.getChildElementsByNameNs(BPMN, "conditionExpression") | ||
.stream() | ||
.map(dom -> { | ||
String language = dom.getAttribute("language"); | ||
if (language == null) { | ||
language = "juel"; | ||
} | ||
return new ConditionExpression(sequenceFlow.getAttribute("id"),language, dom.getTextContent()); | ||
}) | ||
.findFirst() | ||
.orElse(null); | ||
} | ||
|
||
private record ConditionExpression(String id, String language, String expression) {} | ||
} |
1 change: 1 addition & 0 deletions
1
...ces/META-INF/services/org.camunda.community.migration.converter.visitor.DomElementVisitor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
org.camunda.community.migration.example.extendedConverter.CustomDomElementVisitor |
47 changes: 47 additions & 0 deletions
47
...java/org/camunda/community/migration/example/extendedConverter/ExtendedConverterTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package org.camunda.community.migration.example.extendedConverter; | ||
|
||
import org.camunda.bpm.model.bpmn.Bpmn; | ||
import org.camunda.bpm.model.bpmn.BpmnModelInstance; | ||
import org.camunda.community.migration.converter.BpmnConverter; | ||
import org.camunda.community.migration.converter.BpmnConverterFactory; | ||
import org.camunda.community.migration.converter.ConverterPropertiesFactory; | ||
import org.camunda.community.migration.converter.DomElementVisitorFactory; | ||
import org.camunda.community.migration.converter.visitor.DomElementVisitor; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import java.io.StringWriter; | ||
import java.util.List; | ||
|
||
import static org.assertj.core.api.Assertions.*; | ||
|
||
public class ExtendedConverterTest { | ||
private static BpmnModelInstance loadModelInstance(String bpmnFile) { | ||
return Bpmn.readModelFromStream(ExtendedConverterTest.class | ||
.getClassLoader() | ||
.getResourceAsStream(bpmnFile)); | ||
} | ||
|
||
@Test | ||
void shouldLoadCustomDomElementVisitor() { | ||
List<DomElementVisitor> domElementVisitors = DomElementVisitorFactory | ||
.getInstance() | ||
.get(); | ||
assertThat(domElementVisitors).hasAtLeastOneElementOfType(CustomDomElementVisitor.class); | ||
} | ||
|
||
@Test | ||
void shouldAddPropertiesToGateway() { | ||
BpmnConverter converter = BpmnConverterFactory | ||
.getInstance() | ||
.get(); | ||
BpmnModelInstance modelInstance = loadModelInstance("example-model.bpmn"); | ||
converter.convert(modelInstance, | ||
ConverterPropertiesFactory | ||
.getInstance() | ||
.get() | ||
); | ||
StringWriter writer = new StringWriter(); | ||
converter.printXml(modelInstance.getDocument(),true,writer); | ||
System.out.println(writer); | ||
} | ||
} |
Oops, something went wrong.