Skip to content

Commit

Permalink
Feature: Converter is now version-aware (#116)
Browse files Browse the repository at this point in the history
* Added comparison tooling for semver

* Adjusted message to respect platform version

* Terminate End Event is supported in 8.1.0

* Created new message for inclusive gateway

* Inclusive gateway forking is supported in 8.1.0

* Changed default version to 8.1.0

* Added platformVersion parameter to REST and CLI

* Adjusted docs

* Adjusted message and behaviour

* formatter
  • Loading branch information
jonathanlukas authored Nov 28, 2022
1 parent 15b5936 commit f3c1308
Show file tree
Hide file tree
Showing 20 changed files with 370 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ public abstract class AbstractConvertCommand implements Callable<Integer> {
description = "If enabled, existing files are overridden")
boolean override;

@Option(
names = {"--platform-version"},
description = "Semantic version of the target platform, defaults to latest version")
String platformVersion;

public AbstractConvertCommand() {
BpmnConverterFactory factory = BpmnConverterFactory.getInstance();
factory.getNotificationServiceFactory().setInstance(new PrintNotificationServiceImpl());
Expand Down Expand Up @@ -84,6 +89,7 @@ private int handleModel(File file, BpmnModelInstance modelInstance) {
protected DefaultConverterProperties converterProperties() {
DefaultConverterProperties properties = new DefaultConverterProperties();
properties.setAdapterJobType(adapterJobType);
properties.setPlatformVersion(platformVersion);
return properties;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ public class MessageFactory {

private MessageFactory() {}

public static Message inclusiveGatewayJoin() {
return INSTANCE.staticMessage("inclusive-gateway-join");
}

public static Message collectionHint() {
return INSTANCE.staticMessage("collection-hint");
}
Expand All @@ -21,10 +25,12 @@ public static Message callActivityNoCalledElementHint() {
return INSTANCE.staticMessage("call-activity-no-called-element-hint");
}

public static Message elementNotSupportedHint(String elementLocalName) {
public static Message elementNotSupportedHint(String elementLocalName, String semanticVersion) {
return INSTANCE.composeMessage(
"element-not-supported-hint",
ContextBuilder.builder().context(elementNotSupportedPrefix(elementLocalName)).build());
ContextBuilder.builder()
.context(elementNotSupportedPrefix(elementLocalName, semanticVersion))
.build());
}

public static Message completionCondition(ExpressionTransformationResult transformationResult) {
Expand Down Expand Up @@ -171,10 +177,12 @@ public static Message elementCanBeUsed(String elementLocalName) {
ContextBuilder.builder().context(elementCanBeUsedPrefix(elementLocalName)).build());
}

public static Message elementNotSupported(String elementLocalName) {
public static Message elementNotSupported(String elementLocalName, String semanticVersion) {
return INSTANCE.composeMessage(
"element-not-supported",
ContextBuilder.builder().context(elementNotSupportedPrefix(elementLocalName)).build());
ContextBuilder.builder()
.context(elementNotSupportedPrefix(elementLocalName, semanticVersion))
.build());
}

public static Message script() {
Expand Down Expand Up @@ -435,8 +443,12 @@ private static Map<String, String> supportedAttributePrefix(
.build();
}

private static Map<String, String> elementNotSupportedPrefix(String elementLocalName) {
return ContextBuilder.builder().entry("elementLocalName", elementLocalName).build();
private static Map<String, String> elementNotSupportedPrefix(
String elementLocalName, String semanticVersion) {
return ContextBuilder.builder()
.entry("elementLocalName", elementLocalName)
.entry("semanticVersion", semanticVersion)
.build();
}

private static Map<String, String> elementTransformedPrefix(String elementLocalName) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.camunda.community.converter.version;

public enum SemanticVersion {
_8_0_0("8.0.0"),
_8_1_0("8.1.0"),
_8_2_0("8.2.0");

private final String name;

SemanticVersion(String name) {
this.name = name;
}

@Override
public String toString() {
return name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.camunda.community.converter.version;

import java.util.Comparator;

public class VersionComparator implements Comparator<int[]> {

@Override
public int compare(int[] version1, int[] version2) {
int positionsToCompare = Math.min(version1.length, version2.length);
int comparison = 0;
for (int i = 0; i < positionsToCompare; i++) {
comparison = version1[i] - version2[i];
if (comparison != 0) {
return comparison;
}
}
return comparison;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.camunda.community.converter.version;

public class VersionComparison {
private static final VersionComparator VERSION_COMPARATOR = new VersionComparator();
private static final VersionExtractor VERSION_EXTRACTOR = new VersionExtractor();

public static boolean isSupported(String actualVersion, String requiredVersion) {
return VERSION_COMPARATOR.compare(
VERSION_EXTRACTOR.apply(actualVersion), VERSION_EXTRACTOR.apply(requiredVersion))
>= 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.camunda.community.converter.version;

import java.util.Arrays;
import java.util.function.Function;

public class VersionExtractor implements Function<String, int[]> {
@Override
public int[] apply(String version) {
return Arrays.stream(version.split("\\.")).mapToInt(Integer::valueOf).toArray();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ protected final void visitFilteredElement(DomElementVisitorContext context) {
} else {
context.addMessage(
Severity.WARNING,
MessageFactory.elementNotSupported(context.getElement().getLocalName()));
MessageFactory.elementNotSupported(
context.getElement().getLocalName(), context.getProperties().getPlatformVersion()));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ protected final void visitFilteredElement(DomElementVisitorContext context) {
context.setAsBpmnProcessElement(createConvertible(context));
postCreationVisitor(context);
if (!canBeConverted(context)) {
context.addMessage(
Severity.WARNING,
MessageFactory.elementNotSupportedHint(context.getElement().getLocalName()));
addCannotBeConvertedMessage(context);
}
}

Expand All @@ -30,4 +28,11 @@ protected final void visitFilteredElement(DomElementVisitorContext context) {
protected void postCreationVisitor(DomElementVisitorContext context) {
// do nothing
}

protected void addCannotBeConvertedMessage(DomElementVisitorContext context) {
context.addMessage(
Severity.WARNING,
MessageFactory.elementNotSupportedHint(
context.getElement().getLocalName(), context.getProperties().getPlatformVersion()));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.camunda.community.converter.visitor.impl.eventDefinition;

import org.camunda.community.converter.DomElementVisitorContext;
import org.camunda.community.converter.version.SemanticVersion;
import org.camunda.community.converter.version.VersionComparison;
import org.camunda.community.converter.visitor.AbstractEventDefinitionVisitor;

public class TerminateEventDefinitionVisitor extends AbstractEventDefinitionVisitor {
Expand All @@ -9,9 +11,9 @@ public String localName() {
return "terminateEventDefinition";
}

// TODO this is supported in 8.1
@Override
public boolean canBeConverted(DomElementVisitorContext context) {
return false;
return VersionComparison.isSupported(
context.getProperties().getPlatformVersion(), SemanticVersion._8_1_0.toString());
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
package org.camunda.community.converter.visitor.impl.gateway;

import org.camunda.bpm.model.xml.instance.DomElement;
import org.camunda.community.converter.BpmnDiagramCheckResult.Severity;
import org.camunda.community.converter.DomElementVisitorContext;
import org.camunda.community.converter.NamespaceUri;
import org.camunda.community.converter.convertible.Convertible;
import org.camunda.community.converter.convertible.InclusiveGatewayConvertible;
import org.camunda.community.converter.message.MessageFactory;
import org.camunda.community.converter.version.SemanticVersion;
import org.camunda.community.converter.version.VersionComparison;
import org.camunda.community.converter.visitor.AbstractGatewayVisitor;

public class InclusiveGatewayVisitor extends AbstractGatewayVisitor {
Expand All @@ -11,14 +17,35 @@ public String localName() {
return "inclusiveGateway";
}

// TODO this is supported in 8.1 (forking only)
@Override
public boolean canBeConverted(DomElementVisitorContext context) {
return false;
return isNotJoining(context.getElement()) && isRequiredVersion(context);
}

private boolean isRequiredVersion(DomElementVisitorContext context) {
return VersionComparison.isSupported(
context.getProperties().getPlatformVersion(), SemanticVersion._8_1_0.toString());
}

private boolean isNotJoining(DomElement element) {
return element.getChildElements().stream()
.filter(e -> e.getNamespaceURI().equals(NamespaceUri.BPMN))
.filter(e -> e.getLocalName().equals("incoming"))
.count()
<= 1;
}

@Override
protected Convertible createConvertible(DomElementVisitorContext context) {
return new InclusiveGatewayConvertible();
}

@Override
protected void addCannotBeConvertedMessage(DomElementVisitorContext context) {
if (!isRequiredVersion(context)) {
super.addCannotBeConvertedMessage(context);
} else {
context.addMessage(Severity.WARNING, MessageFactory.inclusiveGatewayJoin());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ zeebe-header.resource=resource
## Script format
zeebe-header.script-format=scriptFormat
# Zeebe Meta Information
zeebe-platform.version=8.0.0
zeebe-platform.version=8.1.0
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ expression-transformation-result=Please review transformed expression: '{{ oldEx
supported-attribute-prefix=Attribute '{{ attributeLocalName }}' on '{{ elementLocalName }}' was mapped.
supported-attribute-expression={{ templates.supported-attribute-prefix }} {{ templates.expression-transformation-result }}
attribute-not-supported-prefix=Attribute '{{ attributeLocalName }}' on '{{ elementLocalName }}' is currently not supported.
element-not-supported-prefix=Element '{{ elementLocalName }}' is currently not supported in Zeebe.
element-not-supported-prefix=Element '{{ elementLocalName }}' is not supported in Zeebe version '{{ semanticVersion }}'.
element-not-transformable-prefix=Element '{{ elementLocalName }}' cannot be transformed.
element-transformed-prefix=Element '{{ elementLocalName }}' was transformed.
element-can-be-used-prefix=Element '{{ elementLocalName }}' can be used.
Expand Down Expand Up @@ -58,6 +58,7 @@ element-can-be-used={{ templates.element-can-be-used-prefix }}
element-not-supported={{ templates.element-not-supported-prefix }}
script=Script was set to header 'script'. Please review.
loop-cardinality=Loop cardinality is currently not supported
inclusive-gateway-join=A joining inclusive gateway is not supported.
# BPMN attribute
script-format=Script format '{{ scriptFormat }}' was set to header '{{ headerName }}'. Please review.
script-format-missing=Script format could not be found. Please review.
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,50 @@ public void testTaskListenerHints() {
.isEqualTo(
"Element 'script' cannot be transformed. Script 'delegateTask.setName(\"my script name\");' with format 'javascript' on 'taskListener'.");
}

@Test
void testOrGateways() {
BpmnConverter converter = BpmnConverterFactory.getInstance().get();
BpmnModelInstance modelInstance =
Bpmn.readModelFromStream(
getClass().getClassLoader().getResourceAsStream("or-gateways.bpmn"));
DefaultConverterProperties properties = new DefaultConverterProperties();
properties.setPlatformVersion("8.0.0");
BpmnDiagramCheckResult result =
converter.check(
"or-gateways.bpmn",
modelInstance,
false,
ConverterPropertiesFactory.getInstance().merge(properties));
BpmnElementCheckResult forkGateway = result.getResult("ForkGateway");
assertThat(forkGateway.getMessages()).hasSize(1);
assertThat(forkGateway.getMessages().get(0).getMessage())
.isEqualTo(
"Element 'inclusiveGateway' is not supported in Zeebe version '8.0.0'. Please review.");
BpmnElementCheckResult joinGateway = result.getResult("JoinGateway");
assertThat(joinGateway.getMessages()).hasSize(1);
assertThat(joinGateway.getMessages().get(0).getMessage())
.isEqualTo(
"Element 'inclusiveGateway' is not supported in Zeebe version '8.0.0'. Please review.");
}

@Test
void testOrGateways_8_1() {
BpmnConverter converter = BpmnConverterFactory.getInstance().get();
BpmnModelInstance modelInstance =
Bpmn.readModelFromStream(
getClass().getClassLoader().getResourceAsStream("or-gateways.bpmn"));
DefaultConverterProperties properties = new DefaultConverterProperties();
properties.setPlatformVersion("8.1.0");
BpmnDiagramCheckResult result =
converter.check(
"or-gateways.bpmn",
modelInstance,
false,
ConverterPropertiesFactory.getInstance().merge(properties));
BpmnElementCheckResult joinGateway = result.getResult("JoinGateway");
assertThat(joinGateway.getMessages()).hasSize(1);
assertThat(joinGateway.getMessages().get(0).getMessage())
.isEqualTo("A joining inclusive gateway is not supported.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ void shouldBuildScriptJobType() {
assertNotNull(message.getMessage());
}

@Test
void shouldBuildInclusiveGatewayJoin() {
Message message = MessageFactory.inclusiveGatewayJoin();
assertNotNull(message);
assertNotNull(message.getMessage());
}

@Test
void shouldBuildMap() {
Message message = MessageFactory.map();
Expand Down Expand Up @@ -169,7 +176,7 @@ void shouldBuildElementCanBeUsed() {

@Test
void shouldBuildElementNotSupported() {
Message message = MessageFactory.elementNotSupported(random());
Message message = MessageFactory.elementNotSupported(random(), random());
assertNotNull(message);
assertNotNull(message.getMessage());
}
Expand Down Expand Up @@ -357,7 +364,7 @@ void shouldBuildExecutionListener() {

@Test
void shouldBuildElementNotSupportedHint() {
Message message = MessageFactory.elementNotSupportedHint(random());
Message message = MessageFactory.elementNotSupportedHint(random(), random());
assertNotNull(message);
assertNotNull(message.getMessage());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.camunda.community.converter.version;

import static org.assertj.core.api.Assertions.*;

import org.junit.jupiter.api.Test;

public class VersionComparatorTest {

@Test
void shouldFindEqualVersion() {
int[] version1 = new int[] {8, 0, 0};
int[] version2 = new int[] {8, 0};
VersionComparator comparator = new VersionComparator();
int compare = comparator.compare(version1, version2);
assertThat(compare).isEqualTo(0);
}

@Test
void shouldFindBiggerVersion() {
int[] version1 = new int[] {8, 1, 0};
int[] version2 = new int[] {8, 0};
VersionComparator comparator = new VersionComparator();
int compare = comparator.compare(version1, version2);
assertThat(compare).isEqualTo(1);
}

@Test
void shouldFindSmallerVersion() {
int[] version1 = new int[] {0, 26, 0};
int[] version2 = new int[] {8, 1};
VersionComparator comparator = new VersionComparator();
int compare = comparator.compare(version1, version2);
assertThat(compare).isEqualTo(-8);
}
}
Loading

0 comments on commit f3c1308

Please sign in to comment.