diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000..06541a8b
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,14 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+ - package-ecosystem: "maven" # See documentation for possible values
+ directory: "/" # Location of package manifests
+ schedule:
+ interval: "weekly"
+ assignees:
+ - ricardozanini
+ - tsurdilo
diff --git a/.github/project.yml b/.github/project.yml
new file mode 100644
index 00000000..a69b4050
--- /dev/null
+++ b/.github/project.yml
@@ -0,0 +1,3 @@
+release:
+ current-version: 4.0.5
+ next-version: 5.0.0-SNAPSHOT
\ No newline at end of file
diff --git a/.github/workflows/maven-deploy.yml b/.github/workflows/maven-deploy.yml
deleted file mode 100644
index 67812473..00000000
--- a/.github/workflows/maven-deploy.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-# This workflow will build a Java project with Maven
-# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
-
-name: Deploy JAVA SDK
-
-on:
- push:
- branches:
- - main
-jobs:
- publish:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- - name: Set up Maven Central Repository
- uses: actions/setup-java@v1
- with:
- java-version: 1.8
- server-id: ossrh
- server-username: MAVEN_USERNAME
- server-password: MAVEN_PASSWORD
- - name: Publish package
- run: mvn -B -f pom.xml deploy
- env:
- MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
- MAVEN_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
diff --git a/.github/workflows/maven-verify.yml b/.github/workflows/maven-verify.yml
index 5da52578..44aba632 100644
--- a/.github/workflows/maven-verify.yml
+++ b/.github/workflows/maven-verify.yml
@@ -1,30 +1,28 @@
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
-name: Verify JAVA SDK
+name: sdk-java Verify
on:
push:
branches:
- - main
+ - 4.0.*
pull_request:
branches:
- - main
+ - 4.0.*
jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
- - name: Set up JDK 1.8
- uses: actions/setup-java@v1
- with:
- java-version: 1.8
- - name: Cache Maven packages
- uses: actions/cache@v2
- with:
- path: ~/.m2
- key: ${{ runner.os }}-m2-${{ hashFiles('pom.xml') }}
- restore-keys: ${{ runner.os }}-m2
- - name: Verify with Maven
- run: |
- mvn -B -f pom.xml clean install verify
+ - uses: actions/checkout@v2
+
+ - name: Set up JDK 1.8
+ uses: actions/setup-java@v3
+ with:
+ distribution: temurin
+ java-version: 8
+ cache: 'maven'
+
+ - name: Verify with Maven
+ run: |
+ mvn -B -f pom.xml clean install verify
diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml
new file mode 100644
index 00000000..ce904c75
--- /dev/null
+++ b/.github/workflows/pre-release.yml
@@ -0,0 +1,25 @@
+name: sdk-java Pre Release
+
+on:
+ pull_request:
+ paths:
+ - '.github/project.yml'
+
+jobs:
+ release:
+ runs-on: ubuntu-latest
+ name: pre release
+
+ steps:
+ - uses: radcortez/project-metadata-action@master
+ name: retrieve project metadata
+ id: metadata
+ with:
+ github-token: ${{secrets.GITHUB_TOKEN}}
+ metadata-file-path: '.github/project.yml'
+
+ - name: Validate version
+ if: contains(steps.metadata.outputs.current-version, 'SNAPSHOT')
+ run: |
+ echo '::error::Cannot release a SNAPSHOT version.'
+ exit 1
\ No newline at end of file
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 00000000..f2341c8a
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,58 @@
+name: sdk-java Release
+
+on:
+ pull_request:
+ types: [closed]
+ paths:
+ - '.github/project.yml'
+
+jobs:
+ release:
+ runs-on: ubuntu-latest
+ name: release
+ if: ${{github.event.pull_request.merged == true}}
+
+ steps:
+ - uses: radcortez/project-metadata-action@main
+ name: Retrieve project metadata
+ id: metadata
+ with:
+ github-token: ${{secrets.GITHUB_TOKEN}}
+ metadata-file-path: '.github/project.yml'
+
+ - uses: actions/checkout@v3
+
+ - name: Import GPG key
+ id: import_gpg
+ uses: crazy-max/ghaction-import-gpg@v5
+ with:
+ gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
+ passphrase: ${{ secrets.GPG_PASSPHRASE }}
+
+ - name: Set up JDK 1.8
+ uses: actions/setup-java@v3
+ with:
+ distribution: temurin
+ java-version: 8
+ cache: 'maven'
+ server-id: ossrh
+ server-username: MAVEN_USERNAME
+ server-password: MAVEN_PASSWORD
+
+ - name: Configure Git author
+ run: |
+ git config --local user.email "action@github.com"
+ git config --local user.name "GitHub Action"
+
+ - name: Maven release ${{steps.metadata.outputs.current-version}}
+ run: |
+ mvn -B release:prepare -Prelease -DreleaseVersion=${{steps.metadata.outputs.current-version}} -DdevelopmentVersion=${{steps.metadata.outputs.next-version}}
+ mvn -B release:perform -Darguments=-DperformRelease -DperformRelease -Prelease
+ env:
+ MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
+ MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
+
+ - name: Push changes to ${{github.base_ref}} branch
+ run: |
+ git push
+ git push origin ${{steps.metadata.outputs.current-version}}
diff --git a/api/pom.xml b/api/pom.xml
index 8b27e853..63ba1ef1 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -26,31 +26,19 @@
com.fasterxml.jackson.core
jackson-core
- [2.13.0,)
com.fasterxml.jackson.core
jackson-databind
- [2.13.0,)
com.fasterxml.jackson.dataformat
jackson-dataformat-yaml
- [2.13.0,)
javax.validation
validation-api
-
- org.json
- json
-
-
- com.github.erosb
- everit-json-schema
-
-
org.junit.jupiter
diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/AuthDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/AuthDeserializer.java
index abdb0583..aa078cb4 100644
--- a/api/src/main/java/io/serverlessworkflow/api/deserializers/AuthDeserializer.java
+++ b/api/src/main/java/io/serverlessworkflow/api/deserializers/AuthDeserializer.java
@@ -20,7 +20,6 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import io.serverlessworkflow.api.auth.AuthDefinition;
import io.serverlessworkflow.api.interfaces.WorkflowPropertySource;
import io.serverlessworkflow.api.utils.Utils;
@@ -28,7 +27,6 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -69,21 +67,8 @@ public Auth deserialize(JsonParser jp, DeserializationContext ctxt) throws IOExc
} else {
String authFileDef = node.asText();
String authFileSrc = Utils.getResourceFileAsString(authFileDef);
- JsonNode authRefNode;
- ObjectMapper jsonWriter = new ObjectMapper();
if (authFileSrc != null && authFileSrc.trim().length() > 0) {
- // if its a yaml def convert to json first
- if (!authFileSrc.trim().startsWith("{")) {
- // convert yaml to json to validate
- ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
- Object obj = yamlReader.readValue(authFileSrc, Object.class);
-
- authRefNode =
- jsonWriter.readTree(new JSONObject(jsonWriter.writeValueAsString(obj)).toString());
- } else {
- authRefNode = jsonWriter.readTree(new JSONObject(authFileSrc).toString());
- }
-
+ JsonNode authRefNode = Utils.getNode(authFileSrc);
JsonNode refAuth = authRefNode.get("auth");
if (refAuth != null) {
for (final JsonNode nodeEle : refAuth) {
diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/ConstantsDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/ConstantsDeserializer.java
index c3789b52..3859273c 100644
--- a/api/src/main/java/io/serverlessworkflow/api/deserializers/ConstantsDeserializer.java
+++ b/api/src/main/java/io/serverlessworkflow/api/deserializers/ConstantsDeserializer.java
@@ -18,14 +18,11 @@
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import io.serverlessworkflow.api.interfaces.WorkflowPropertySource;
import io.serverlessworkflow.api.utils.Utils;
import io.serverlessworkflow.api.workflow.Constants;
import java.io.IOException;
-import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,21 +60,8 @@ public Constants deserialize(JsonParser jp, DeserializationContext ctxt) throws
} else {
String constantsFileDef = node.asText();
String constantsFileSrc = Utils.getResourceFileAsString(constantsFileDef);
- JsonNode constantsRefNode;
- ObjectMapper jsonWriter = new ObjectMapper();
if (constantsFileSrc != null && constantsFileSrc.trim().length() > 0) {
- // if its a yaml def convert to json first
- if (!constantsFileSrc.trim().startsWith("{")) {
- // convert yaml to json to validate
- ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
- Object obj = yamlReader.readValue(constantsFileSrc, Object.class);
-
- constantsRefNode =
- jsonWriter.readTree(new JSONObject(jsonWriter.writeValueAsString(obj)).toString());
- } else {
- constantsRefNode = jsonWriter.readTree(new JSONObject(constantsFileSrc).toString());
- }
-
+ JsonNode constantsRefNode = Utils.getNode(constantsFileSrc);
JsonNode refConstants = constantsRefNode.get("constants");
if (refConstants != null) {
constantsDefinition = refConstants;
diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/ErrorsDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/ErrorsDeserializer.java
index beedc7dd..6fe366ea 100644
--- a/api/src/main/java/io/serverlessworkflow/api/deserializers/ErrorsDeserializer.java
+++ b/api/src/main/java/io/serverlessworkflow/api/deserializers/ErrorsDeserializer.java
@@ -20,7 +20,6 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import io.serverlessworkflow.api.error.ErrorDefinition;
import io.serverlessworkflow.api.interfaces.WorkflowPropertySource;
import io.serverlessworkflow.api.utils.Utils;
@@ -28,7 +27,6 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -69,21 +67,8 @@ public Errors deserialize(JsonParser jp, DeserializationContext ctxt) throws IOE
} else {
String errorsFileDef = node.asText();
String errorsFileSrc = Utils.getResourceFileAsString(errorsFileDef);
- JsonNode errorsRefNode;
- ObjectMapper jsonWriter = new ObjectMapper();
if (errorsFileSrc != null && errorsFileSrc.trim().length() > 0) {
- // if its a yaml def convert to json first
- if (!errorsFileSrc.trim().startsWith("{")) {
- // convert yaml to json to validate
- ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
- Object obj = yamlReader.readValue(errorsFileSrc, Object.class);
-
- errorsRefNode =
- jsonWriter.readTree(new JSONObject(jsonWriter.writeValueAsString(obj)).toString());
- } else {
- errorsRefNode = jsonWriter.readTree(new JSONObject(errorsFileSrc).toString());
- }
-
+ JsonNode errorsRefNode = Utils.getNode(errorsFileSrc);
JsonNode refErrors = errorsRefNode.get("errors");
if (refErrors != null) {
for (final JsonNode nodeEle : refErrors) {
diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/EventsDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/EventsDeserializer.java
index cfa207df..a02fdf4b 100644
--- a/api/src/main/java/io/serverlessworkflow/api/deserializers/EventsDeserializer.java
+++ b/api/src/main/java/io/serverlessworkflow/api/deserializers/EventsDeserializer.java
@@ -20,7 +20,6 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import io.serverlessworkflow.api.events.EventDefinition;
import io.serverlessworkflow.api.interfaces.WorkflowPropertySource;
import io.serverlessworkflow.api.utils.Utils;
@@ -28,7 +27,6 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -69,21 +67,9 @@ public Events deserialize(JsonParser jp, DeserializationContext ctxt) throws IOE
} else {
String eventsFileDef = node.asText();
String eventsFileSrc = Utils.getResourceFileAsString(eventsFileDef);
- JsonNode eventsRefNode;
- ObjectMapper jsonWriter = new ObjectMapper();
if (eventsFileSrc != null && eventsFileSrc.trim().length() > 0) {
// if its a yaml def convert to json first
- if (!eventsFileSrc.trim().startsWith("{")) {
- // convert yaml to json to validate
- ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
- Object obj = yamlReader.readValue(eventsFileSrc, Object.class);
-
- eventsRefNode =
- jsonWriter.readTree(new JSONObject(jsonWriter.writeValueAsString(obj)).toString());
- } else {
- eventsRefNode = jsonWriter.readTree(new JSONObject(eventsFileSrc).toString());
- }
-
+ JsonNode eventsRefNode = Utils.getNode(eventsFileSrc);
JsonNode refEvents = eventsRefNode.get("events");
if (refEvents != null) {
for (final JsonNode nodeEle : refEvents) {
diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionsDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionsDeserializer.java
index c27e2c48..b706b2d3 100644
--- a/api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionsDeserializer.java
+++ b/api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionsDeserializer.java
@@ -20,7 +20,6 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import io.serverlessworkflow.api.functions.FunctionDefinition;
import io.serverlessworkflow.api.interfaces.WorkflowPropertySource;
import io.serverlessworkflow.api.utils.Utils;
@@ -28,7 +27,6 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -69,20 +67,9 @@ public Functions deserialize(JsonParser jp, DeserializationContext ctxt) throws
String functionsFileDef = node.asText();
String functionsFileSrc = Utils.getResourceFileAsString(functionsFileDef);
JsonNode functionsRefNode;
- ObjectMapper jsonWriter = new ObjectMapper();
if (functionsFileSrc != null && functionsFileSrc.trim().length() > 0) {
// if its a yaml def convert to json first
- if (!functionsFileSrc.trim().startsWith("{")) {
- // convert yaml to json to validate
- ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
- Object obj = yamlReader.readValue(functionsFileSrc, Object.class);
-
- functionsRefNode =
- jsonWriter.readTree(new JSONObject(jsonWriter.writeValueAsString(obj)).toString());
- } else {
- functionsRefNode = jsonWriter.readTree(new JSONObject(functionsFileSrc).toString());
- }
-
+ functionsRefNode = Utils.getNode(functionsFileSrc);
JsonNode refFunctions = functionsRefNode.get("functions");
if (refFunctions != null) {
for (final JsonNode nodeEle : refFunctions) {
diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/RetriesDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/RetriesDeserializer.java
index ff2fe44d..9eb47b5f 100644
--- a/api/src/main/java/io/serverlessworkflow/api/deserializers/RetriesDeserializer.java
+++ b/api/src/main/java/io/serverlessworkflow/api/deserializers/RetriesDeserializer.java
@@ -20,7 +20,6 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import io.serverlessworkflow.api.interfaces.WorkflowPropertySource;
import io.serverlessworkflow.api.retry.RetryDefinition;
import io.serverlessworkflow.api.utils.Utils;
@@ -28,7 +27,6 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -69,21 +67,8 @@ public Retries deserialize(JsonParser jp, DeserializationContext ctxt) throws IO
} else {
String retriesFileDef = node.asText();
String retriesFileSrc = Utils.getResourceFileAsString(retriesFileDef);
- JsonNode retriesRefNode;
- ObjectMapper jsonWriter = new ObjectMapper();
if (retriesFileSrc != null && retriesFileSrc.trim().length() > 0) {
- // if its a yaml def convert to json first
- if (!retriesFileSrc.trim().startsWith("{")) {
- // convert yaml to json to validate
- ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
- Object obj = yamlReader.readValue(retriesFileSrc, Object.class);
-
- retriesRefNode =
- jsonWriter.readTree(new JSONObject(jsonWriter.writeValueAsString(obj)).toString());
- } else {
- retriesRefNode = jsonWriter.readTree(new JSONObject(retriesFileSrc).toString());
- }
-
+ JsonNode retriesRefNode = Utils.getNode(retriesFileSrc);
JsonNode refRetries = retriesRefNode.get("retries");
if (refRetries != null) {
for (final JsonNode nodeEle : refRetries) {
diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/SecretsDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/SecretsDeserializer.java
index e9ec05e7..60cc2a82 100644
--- a/api/src/main/java/io/serverlessworkflow/api/deserializers/SecretsDeserializer.java
+++ b/api/src/main/java/io/serverlessworkflow/api/deserializers/SecretsDeserializer.java
@@ -18,16 +18,13 @@
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import io.serverlessworkflow.api.interfaces.WorkflowPropertySource;
import io.serverlessworkflow.api.utils.Utils;
import io.serverlessworkflow.api.workflow.Secrets;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -66,21 +63,9 @@ public Secrets deserialize(JsonParser jp, DeserializationContext ctxt) throws IO
} else {
String secretsFileDef = node.asText();
String secretsFileSrc = Utils.getResourceFileAsString(secretsFileDef);
- JsonNode secretsRefNode;
- ObjectMapper jsonWriter = new ObjectMapper();
if (secretsFileSrc != null && secretsFileSrc.trim().length() > 0) {
// if its a yaml def convert to json first
- if (!secretsFileSrc.trim().startsWith("{")) {
- // convert yaml to json to validate
- ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
- Object obj = yamlReader.readValue(secretsFileSrc, Object.class);
-
- secretsRefNode =
- jsonWriter.readTree(new JSONObject(jsonWriter.writeValueAsString(obj)).toString());
- } else {
- secretsRefNode = jsonWriter.readTree(new JSONObject(secretsFileSrc).toString());
- }
-
+ JsonNode secretsRefNode = Utils.getNode(secretsFileSrc);
JsonNode refSecrets = secretsRefNode.get("secrets");
if (refSecrets != null) {
for (final JsonNode nodeEle : refSecrets) {
diff --git a/api/src/main/java/io/serverlessworkflow/api/mapper/JsonObjectMapperFactory.java b/api/src/main/java/io/serverlessworkflow/api/mapper/JsonObjectMapperFactory.java
new file mode 100644
index 00000000..eb34b0eb
--- /dev/null
+++ b/api/src/main/java/io/serverlessworkflow/api/mapper/JsonObjectMapperFactory.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020-Present The Serverless Workflow Specification Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.serverlessworkflow.api.mapper;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class JsonObjectMapperFactory {
+
+ private static final ObjectMapper instance = new JsonObjectMapper();
+
+ public static final ObjectMapper mapper() {
+ return instance;
+ }
+}
diff --git a/api/src/main/java/io/serverlessworkflow/api/mapper/YamlObjectMapperFactory.java b/api/src/main/java/io/serverlessworkflow/api/mapper/YamlObjectMapperFactory.java
new file mode 100644
index 00000000..04371db4
--- /dev/null
+++ b/api/src/main/java/io/serverlessworkflow/api/mapper/YamlObjectMapperFactory.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020-Present The Serverless Workflow Specification Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.serverlessworkflow.api.mapper;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class YamlObjectMapperFactory {
+
+ private static final ObjectMapper instance = new YamlObjectMapper();
+
+ public static final ObjectMapper mapper() {
+ return instance;
+ }
+}
diff --git a/api/src/main/java/io/serverlessworkflow/api/schemaclient/ResourceSchemaClient.java b/api/src/main/java/io/serverlessworkflow/api/schemaclient/ResourceSchemaClient.java
deleted file mode 100644
index a4da2387..00000000
--- a/api/src/main/java/io/serverlessworkflow/api/schemaclient/ResourceSchemaClient.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2020-Present The Serverless Workflow Specification Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package io.serverlessworkflow.api.schemaclient;
-
-import java.io.InputStream;
-import java.util.Objects;
-import org.everit.json.schema.loader.SchemaClient;
-
-public class ResourceSchemaClient implements SchemaClient {
-
- @SuppressWarnings("unused")
- private final SchemaClient fallbackClient;
-
- private final String baseResourcePath = "/schema/";
-
- public ResourceSchemaClient(SchemaClient fallbackClient) {
- this.fallbackClient = Objects.requireNonNull(fallbackClient, "fallbackClient cannot be null");
- }
-
- @Override
- public InputStream get(String path) {
- path = path.substring("https://wg-serverless.org/".length());
- return this.getClass().getResourceAsStream(baseResourcePath + path);
- }
-}
diff --git a/api/src/main/java/io/serverlessworkflow/api/utils/Utils.java b/api/src/main/java/io/serverlessworkflow/api/utils/Utils.java
index 3e4b4274..9bdce416 100644
--- a/api/src/main/java/io/serverlessworkflow/api/utils/Utils.java
+++ b/api/src/main/java/io/serverlessworkflow/api/utils/Utils.java
@@ -15,6 +15,11 @@
*/
package io.serverlessworkflow.api.utils;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.serverlessworkflow.api.mapper.JsonObjectMapperFactory;
+import io.serverlessworkflow.api.mapper.YamlObjectMapperFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
@@ -34,4 +39,14 @@ public static String getResourceFileAsString(String fileName) throws IOException
}
}
}
+
+ public static ObjectMapper getObjectMapper(String source) {
+ return !source.trim().startsWith("{")
+ ? YamlObjectMapperFactory.mapper()
+ : JsonObjectMapperFactory.mapper();
+ }
+
+ public static JsonNode getNode(String source) throws JsonProcessingException {
+ return getObjectMapper(source).readTree(source);
+ }
}
diff --git a/api/src/main/java/io/serverlessworkflow/api/validation/WorkflowSchemaLoader.java b/api/src/main/java/io/serverlessworkflow/api/validation/WorkflowSchemaLoader.java
index 830bb50a..847380fb 100644
--- a/api/src/main/java/io/serverlessworkflow/api/validation/WorkflowSchemaLoader.java
+++ b/api/src/main/java/io/serverlessworkflow/api/validation/WorkflowSchemaLoader.java
@@ -15,26 +15,23 @@
*/
package io.serverlessworkflow.api.validation;
-import io.serverlessworkflow.api.schemaclient.ResourceSchemaClient;
-import org.everit.json.schema.Schema;
-import org.everit.json.schema.loader.SchemaLoader;
-import org.everit.json.schema.loader.internal.DefaultSchemaClient;
-import org.json.JSONObject;
-import org.json.JSONTokener;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.io.UncheckedIOException;
public class WorkflowSchemaLoader {
- private static final JSONObject workflowSchema =
- new JSONObject(
- new JSONTokener(WorkflowSchemaLoader.class.getResourceAsStream("/schema/workflow.json")));
- public static Schema getWorkflowSchema() {
- SchemaLoader schemaLoader =
- SchemaLoader.builder()
- .schemaClient(new ResourceSchemaClient(new DefaultSchemaClient()))
- .schemaJson(workflowSchema)
- .resolutionScope("classpath:schema")
- .draftV7Support()
- .build();
- return schemaLoader.load().build();
+ public static JsonNode getWorkflowSchema() {
+ try {
+ return ObjectMapperHolder.objectMapper.readTree(
+ WorkflowSchemaLoader.class.getResourceAsStream("/schema/workflow.json"));
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ private static class ObjectMapperHolder {
+ public static final ObjectMapper objectMapper = new ObjectMapper();
}
}
diff --git a/api/src/main/resources/schema/produce/produceevent.json b/api/src/main/resources/schema/produce/produceevent.json
index b5bb7d5f..f094824e 100644
--- a/api/src/main/resources/schema/produce/produceevent.json
+++ b/api/src/main/resources/schema/produce/produceevent.json
@@ -10,6 +10,11 @@
"data": {
"type": "string",
"description": "Workflow expression which selects parts of the states data output to become the data of the produced event"
+ },
+ "contextAttributes": {
+ "type": "object",
+ "description": "Add additional event extension context attributes",
+ "existingJavaType": "java.util.Map"
}
},
"required": [
diff --git a/api/src/main/resources/schema/workflow.json b/api/src/main/resources/schema/workflow.json
index 3ed9ce58..f8309b6c 100644
--- a/api/src/main/resources/schema/workflow.json
+++ b/api/src/main/resources/schema/workflow.json
@@ -1,5 +1,5 @@
{
- "$id": "https://wg-serverless.org/workflow.schema.json",
+ "$id": "classpath:schema/workflow.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Serverless Workflow is a vendor-neutral specification for defining the model of workflows responsible for orchestrating event-driven serverless applications.",
"type": "object",
@@ -11,7 +11,8 @@
"properties": {
"id": {
"type": "string",
- "description": "Workflow unique identifier"
+ "description": "Workflow unique identifier",
+ "minLength": 1
},
"key": {
"type": "string",
@@ -159,6 +160,7 @@
}
},
"required": [
+ "id",
"name",
"version",
"states"
diff --git a/api/src/test/java/io/serverlessworkflow/api/test/MarkupToWorkflowTest.java b/api/src/test/java/io/serverlessworkflow/api/test/MarkupToWorkflowTest.java
index a1854d43..f5b30d07 100644
--- a/api/src/test/java/io/serverlessworkflow/api/test/MarkupToWorkflowTest.java
+++ b/api/src/test/java/io/serverlessworkflow/api/test/MarkupToWorkflowTest.java
@@ -44,6 +44,7 @@
import io.serverlessworkflow.api.workflow.Retries;
import io.serverlessworkflow.api.workflow.Secrets;
import java.util.List;
+import java.util.Map;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
@@ -264,6 +265,12 @@ public void testTransitions(String workflowLocation) {
assertEquals("RejectApplication", cond2.getTransition().getNextState());
assertNotNull(cond2.getTransition().getProduceEvents());
assertEquals(1, cond2.getTransition().getProduceEvents().size());
+ assertNotNull(cond2.getTransition().getProduceEvents().get(0).getContextAttributes());
+ Map contextAttributes =
+ cond2.getTransition().getProduceEvents().get(0).getContextAttributes();
+ assertEquals(2, contextAttributes.size());
+ assertEquals("IN", contextAttributes.get("order_location"));
+ assertEquals("online", contextAttributes.get("order_type"));
assertFalse(cond2.getTransition().isCompensate());
assertNotNull(switchState.getDefaultCondition());
diff --git a/api/src/test/resources/features/transitions.json b/api/src/test/resources/features/transitions.json
index cacc94af..ed7b7626 100644
--- a/api/src/test/resources/features/transitions.json
+++ b/api/src/test/resources/features/transitions.json
@@ -23,7 +23,11 @@
"produceEvents": [
{
"eventRef": "provisioningCompleteEvent",
- "data": "${ .provisionedOrders }"
+ "data": "${ .provisionedOrders }",
+ "contextAttributes": {
+ "order_location": "IN",
+ "order_type": "online"
+ }
}
]
}
diff --git a/api/src/test/resources/features/transitions.yml b/api/src/test/resources/features/transitions.yml
index 1b89a85f..3ec34ae4 100644
--- a/api/src/test/resources/features/transitions.yml
+++ b/api/src/test/resources/features/transitions.yml
@@ -18,6 +18,9 @@ states:
produceEvents:
- eventRef: provisioningCompleteEvent
data: "${ .provisionedOrders }"
+ contextAttributes:
+ "order_location": "IN"
+ "order_type": "online"
defaultCondition:
transition:
nextState: RejectApplication
diff --git a/code-of-conduct.md b/code-of-conduct.md
index ddd14b6d..97a8526a 100644
--- a/code-of-conduct.md
+++ b/code-of-conduct.md
@@ -1,58 +1,11 @@
-## CNCF Community Code of Conduct v1.0
+# Code of Conduct
-Other languages available:
-- [Chinese/中文](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/zh.md)
-- [German/Deutsch](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/de.md)
-- [Spanish/Español](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/es.md)
-- [French/Français](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/fr.md)
-- [Italian/Italiano](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/it.md)
-- [Japanese/日本語](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/jp.md)
-- [Korean/한국어](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/ko.md)
-- [Ukrainian/Українська](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/uk.md)
-- [Russian/Русский](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/ru.md)
-- [Portuguese/Português](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/pt.md)
-- [Arabic/العربية](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/ar.md)
-- [Polish/Polski](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/pl.md)
+We follow the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md).
-### Contributor Code of Conduct
-
-As contributors and maintainers of this project, and in the interest of fostering
-an open and welcoming community, we pledge to respect all people who contribute
-through reporting issues, posting feature requests, updating documentation,
-submitting pull requests or patches, and other activities.
-
-We are committed to making participation in this project a harassment-free experience for
-everyone, regardless of level of experience, gender, gender identity and expression,
-sexual orientation, disability, personal appearance, body size, race, ethnicity, age,
-religion, or nationality.
-
-Examples of unacceptable behavior by participants include:
-
-* The use of sexualized language or imagery
-* Personal attacks
-* Trolling or insulting/derogatory comments
-* Public or private harassment
-* Publishing others' private information, such as physical or electronic addresses,
- without explicit permission
-* Other unethical or unprofessional conduct.
-
-Project maintainers have the right and responsibility to remove, edit, or reject
-comments, commits, code, wiki edits, issues, and other contributions that are not
-aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers
-commit themselves to fairly and consistently applying these principles to every aspect
-of managing this project. Project maintainers who do not follow or enforce the Code of
-Conduct may be permanently removed from the project team.
-
-This code of conduct applies both within project spaces and in public spaces
-when an individual is representing the project or its community.
-
-Instances of abusive, harassing, or otherwise unacceptable behavior in Kubernetes may be reported by contacting the [Kubernetes Code of Conduct Committee](https://git.k8s.io/community/committee-code-of-conduct) via conduct@kubernetes.io. For other projects, please contact a CNCF project maintainer or our mediator, Mishi Choudhary via mishi@linux.com.
-
-This Code of Conduct is adapted from the Contributor Covenant
-(), version 1.2.0, available at
-
-
-### CNCF Events Code of Conduct
-
-CNCF events are governed by the Linux Foundation [Code of Conduct](https://events.linuxfoundation.org/code-of-conduct/) available on the event page.
-This is designed to be compatible with the above policy and also includes more details on responding to incidents.
\ No newline at end of file
+
+Please contact the [CNCF Code of Conduct Committee](mailto:conduct@cncf.io)
+in order to report violations of the Code of Conduct.
diff --git a/pom.xml b/pom.xml
index 53a2abf3..22486415 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,87 +1,96 @@
-
- 4.0.0
+
+ 4.0.0
- io.serverlessworkflow
- serverlessworkflow-parent
- 4.0.x
- pom
+ io.serverlessworkflow
+ serverlessworkflow-parent
+ 4.0.x
+ pom
- Serverless Workflow :: Parent
- https://serverlessworkflow.io/sdk-java/
- Java SDK for Serverless Workflow Specification
- 2020
-
- CNCF
- https://www.cncf.io//
-
-
-
- The Apache Software License, Version 2.0
- http://www.apache.org/licenses/LICENSE-2.0.txt
- repo
-
-
+ Serverless Workflow :: Parent
+ https://serverlessworkflow.io/sdk-java/
+ Java SDK for Serverless Workflow Specification
+ 2020
+
+
+ serverless-workflow
+ Serverless Workflow Specification Authors
+ CNCF
+
+
+
+ CNCF
+ https://www.cncf.io//
+
+
+
+ The Apache Software License, Version 2.0
+ http://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
+
+ scm:git:git@github.com:serverlessworkflow/sdk-java.git
+ scm:git:git@github.com:serverlessworkflow/sdk-java.git
+ https://github.com/serverlessworkflow/sdk-java
+ HEAD
+
-
- scm:git:git://github.com/serverlessworkflow/sdk-java.git
- scm:git:git@github.com:serverlessworkflow/sdk-java.git
- https://github.com/serverlessworkflow/sdk-java
-
+
+ api
+ spi
+ validation
+ diagram
+ utils
+
-
-
- tsurdilo
- Tihomir Surdilovic
-
-
+
+ 1.8
+ ${java.version}
+ ${java.version}
+ UTF-8
+ 3.6.2
-
- api
- spi
- validation
- diagram
- utils
-
+
+ 3.2.0
+ 3.1.1
+ 3.8.1
+ 2.8.2
+ 3.0.0-M2
+ 3.1.2
+ 2.9.1
+ 3.1.0
+ 3.2.0
+ ${java.version}
+ 1.0.1
+ 3.3.0
+ 2.22.0
-
- 1.8
- 1.8
- 1.8
- UTF-8
- 3.6.2
- 3.0.0-M2
- 8
- 3.8.1
- 2.22.0
- 2.22.0
- 3.1.1
- 2.8.2
- 1.7.25
- 2.10.3
- 2.0.1.Final
- 6.0
- 5.${version.org.junit.minor}
- ${version.org.junit}
- 3.0.0
- 1.4.8
- 3.13.2
- 1.0.1
- 3.9
- 1.3
- 1.5.0
- 1.14.1
- 20230618
- 3.0.11.RELEASE
- 8059
- 0.17.0
- 2.9
- 3.2.0
-
- true
-
+ 1.4.9
+ 2.15.3
+ 1.0.87
+ 3.13.0
+ 0.17.0
+ 1.3
+ 2.0.1.Final
+ 1.5.0
+ 3.13.2
+ ${version.org.junit}
+ 6.0
+ 5.${version.org.junit.minor}
+ 5.6.0
+ 1.7.25
+ 8059
+ 3.1.2.RELEASE
+
+
+
+ true
+
-
- java
- true
-
+
+ java
+ true
+
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${version.org.slf4j}
+
+
+ org.slf4j
+ jcl-over-slf4j
+ ${version.org.slf4j}
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ ${version.com.fasterxml.jackson}
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${version.com.fasterxml.jackson}
+
+
+ com.networknt
+ json-schema-validator
+ ${version.com.networknt}
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-yaml
+ ${version.com.fasterxml.jackson}
+
+
+ javax.validation
+ validation-api
+ ${version.javax.validation}
+
+
+ org.apache.commons
+ commons-lang3
+ ${version.commons.lang}
+
+
+ org.thymeleaf
+ thymeleaf
+ ${version.thymeleaf}
+
+
+ net.sourceforge.plantuml
+ plantuml
+ ${version.plantuml}
+
+
+ guru.nidi
+ graphviz-java
+ ${version.graphviz}
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ ${version.org.junit.jupiter}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ ${version.org.junit.jupiter}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ ${version.org.junit.jupiter}
+ test
+
+
+ org.mockito
+ mockito-core
+ ${version.org.mockito}
+ test
+
+
+ ch.qos.logback
+ logback-classic
+ ${version.ch.qos.logback}
+ test
+
+
+ org.assertj
+ assertj-core
+ ${version.org.assertj}
+ test
+
+
+ org.hamcrest
+ hamcrest-library
+ ${version.hamcrest}
+ test
+
+
+ org.skyscreamer
+ jsonassert
+ ${version.jsonassert}
+ test
+
+
+
-
-
-
- org.slf4j
- slf4j-api
- ${version.org.slf4j}
-
-
- org.slf4j
- jcl-over-slf4j
- ${version.org.slf4j}
-
-
- com.fasterxml.jackson.core
- jackson-core
- ${version.com.fasterxml.jackson}
-
-
- com.fasterxml.jackson.core
- jackson-databind
- ${version.com.fasterxml.jackson}
-
-
- com.fasterxml.jackson.dataformat
- jackson-dataformat-yaml
- ${version.com.fasterxml.jackson}
-
-
- javax.validation
- validation-api
- ${version.javax.validation}
-
-
- org.apache.commons
- commons-lang3
- ${commons.lang.version}
-
-
- com.github.erosb
- everit-json-schema
- ${json.schema.validation.version}
-
-
- commons-logging
- commons-logging
-
-
-
-
- org.json
- json
- ${version.json}
-
-
- org.thymeleaf
- thymeleaf
- ${version.thymeleaf}
-
-
- net.sourceforge.plantuml
- plantuml
- ${version.plantuml}
-
-
- guru.nidi
- graphviz-java
- ${version.graphviz}
-
+
+
+
+
+ org.codehaus.mojo
+ buildnumber-maven-plugin
+ ${version.buildnumber.plugin}
+
+
+ get-scm-revision
+ initialize
+
+ create
+
+
+ false
+ false
+ UNKNOWN
+ true
+
+
+
+
+
+ maven-compiler-plugin
+ ${version.compiler.plugin}
+
+ true
+ true
+ ${maven.compiler.source}
+ ${maven.compiler.target}
+ ${maven.compiler.source}
+ ${maven.compiler.target}
+ true
+
+ -Xlint:unchecked
+
+
+
+
-
-
- org.junit.jupiter
- junit-jupiter-api
- ${version.org.junit.jupiter}
- test
-
-
- org.junit.jupiter
- junit-jupiter-engine
- ${version.org.junit.jupiter}
- test
-
-
- org.junit.jupiter
- junit-jupiter-params
- ${version.org.junit.jupiter}
- test
-
-
- org.mockito
- mockito-core
- ${version.org.mockito}
- test
-
-
- ch.qos.logback
- logback-classic
- ${version.ch.qos.logback}
- test
-
-
- org.assertj
- assertj-core
- ${version.org.assertj}
- test
-
-
- org.hamcrest
- hamcrest-library
- ${hamcrest.version}
- test
-
-
- org.skyscreamer
- jsonassert
- ${jsonassert.version}
- test
-
-
-
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ ${version.gpg.plugin}
+
+
+ maven-deploy-plugin
+ ${version.deploy.plugin}
+
+ 10
+
+
+
+ org.apache.maven.plugins
+ maven-enforcer-plugin
+ ${version.enforcer.plugin}
+
+
+ enforce-versions
+
+ enforce
+
+
+
+
+ ${version.maven}
+
+
+ ${version.jdk}
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ ${version.source.plugin}
+
+
+ attach-sources
+
+ jar-no-fork
+
+
+
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+
+ ${project.url}
+ ${java.version}
+ ${java.vendor}
+ ${os.name}
+ ${os.arch}
+ ${os.version}
+ ${project.scm.url}
+ ${project.scm.connection}
+ ${buildNumber}
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-release-plugin
+ ${version.release.plugin}
+
+ clean install
+ true
+ @{project.version}
+ false
+ true
+ false
+
+
+
+ org.jsonschema2pojo
+ jsonschema2pojo-maven-plugin
+ ${version.jsonschema2pojo-maven-plugin}
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${version.surefire.plugin}
+
+ -Xmx1024m -XX:+IgnoreUnrecognizedVMOptions -XX:MaxPermSize=256m
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ ${version.failsafe.plugin}
+
+ -Xmx1024m -XX:+IgnoreUnrecognizedVMOptions -XX:MaxPermSize=256m
+
+
+
+ org.apache.maven.plugins
+ maven-checkstyle-plugin
+ ${version.checkstyle.plugin}
+
+
+ com.coveo
+ fmt-maven-plugin
+ ${version.fmt-maven-plugin}
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ ${version.jar.plugin}
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+
+ ${project.url}
+ ${java.version}
+ ${java.vendor}
+ ${os.name}
+ ${os.arch}
+ ${os.version}
+ ${project.scm.url}
+ ${project.scm.connection}
+ ${buildNumber}
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ ${version.javadoc.plugin}
+
+
+
+
-
+
+
+
+ ossrh
+ https://oss.sonatype.org/content/repositories/snapshots
+
+
+ ossrh
+ https://oss.sonatype.org/service/local/staging/deploy/maven2/
+
+
+
+
+
+ central
+ Central Repository
+ https://repo.maven.apache.org/maven2
+ default
+
+ false
+
+
+
+
+
+
+ release
+
-
- maven-deploy-plugin
- ${version.deploy.plugin}
-
- 10
-
-
-
- org.apache.maven.plugins
- maven-enforcer-plugin
- ${version.enforcer.plugin}
-
-
- enforce-versions
-
- enforce
-
-
-
-
- ${version.maven}
-
-
- ${version.jdk}
-
-
-
-
-
-
-
- maven-compiler-plugin
- ${version.compiler.plugin}
-
- true
- true
-
- -Xlint:unchecked
-
-
-
-
- org.jsonschema2pojo
- jsonschema2pojo-maven-plugin
- ${version.jsonschema2pojo-maven-plugin}
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
- ${version.surefire.plugin}
-
- -Xmx1024m -XX:+IgnoreUnrecognizedVMOptions -XX:MaxPermSize=256m
-
-
-
- org.apache.maven.plugins
- maven-checkstyle-plugin
- ${version.checkstyle.plugin}
-
-
- com.coveo
- fmt-maven-plugin
- ${version.fmt-maven-plugin}
-
-
- org.apache.maven.plugins
- maven-jar-plugin
- ${version.jar.plugin}
-
-
- org.apache.maven.plugins
- maven-source-plugin
- 3.0.1
-
-
- attach-sources
-
- jar
-
-
-
-
-
- org.apache.maven.plugins
- maven-javadoc-plugin
- 3.5.0
-
- 8
- -Xdoclint:none
-
-
-
- attach-javadocs
-
- jar
-
-
- false
-
-
-
-
-
- org.apache.maven.plugins
- maven-gpg-plugin
- 1.6
-
-
- sign-artifacts
- verify
-
- sign
-
-
-
- --batch
- --pinentry-mode
- loopback
-
-
-
-
-
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+
+
+ --pinentry-mode
+ loopback
+
+
+
+
+ sign-artifacts
+ verify
+
+ sign
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+ package
+
+ jar
+
+
+
+
-
-
-
-
- ossrh
- https://oss.sonatype.org/content/repositories/snapshots
-
-
- ossrh
- https://oss.sonatype.org/service/local/staging/deploy/maven2/
-
-
+
+
+
-
-
- central
- Central Repository
- https://repo.maven.apache.org/maven2
- default
-
- false
-
-
-
\ No newline at end of file
diff --git a/validation/pom.xml b/validation/pom.xml
index 57afbbb5..6b4e808a 100644
--- a/validation/pom.xml
+++ b/validation/pom.xml
@@ -34,12 +34,10 @@
org.apache.commons
commons-lang3
-
- com.github.erosb
- everit-json-schema
+ com.networknt
+ json-schema-validator
-
org.junit.jupiter
diff --git a/validation/src/main/java/io/serverlessworkflow/validation/WorkflowValidatorImpl.java b/validation/src/main/java/io/serverlessworkflow/validation/WorkflowValidatorImpl.java
index abef046b..12e4e915 100644
--- a/validation/src/main/java/io/serverlessworkflow/validation/WorkflowValidatorImpl.java
+++ b/validation/src/main/java/io/serverlessworkflow/validation/WorkflowValidatorImpl.java
@@ -15,8 +15,9 @@
*/
package io.serverlessworkflow.validation;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.networknt.schema.JsonSchemaFactory;
+import com.networknt.schema.SpecVersion.VersionFlag;
import io.serverlessworkflow.api.Workflow;
import io.serverlessworkflow.api.actions.Action;
import io.serverlessworkflow.api.events.EventDefinition;
@@ -27,15 +28,14 @@
import io.serverlessworkflow.api.states.*;
import io.serverlessworkflow.api.switchconditions.DataCondition;
import io.serverlessworkflow.api.switchconditions.EventCondition;
+import io.serverlessworkflow.api.utils.Utils;
import io.serverlessworkflow.api.validation.ValidationError;
import io.serverlessworkflow.api.validation.WorkflowSchemaLoader;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import org.everit.json.schema.Schema;
-import org.everit.json.schema.ValidationException;
-import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -44,7 +44,7 @@ public class WorkflowValidatorImpl implements WorkflowValidator {
private static final Logger logger = LoggerFactory.getLogger(WorkflowValidatorImpl.class);
private boolean schemaValidationEnabled = true;
private List validationErrors = new ArrayList<>();
- private Schema workflowSchema = WorkflowSchemaLoader.getWorkflowSchema();
+ private JsonNode workflowSchema = WorkflowSchemaLoader.getWorkflowSchema();
private String source;
private Workflow workflow;
@@ -66,34 +66,13 @@ public List validate() {
if (workflow == null) {
try {
if (schemaValidationEnabled && source != null) {
- try {
- if (!source.trim().startsWith("{")) {
- // convert yaml to json to validate
- ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
- Object obj = yamlReader.readValue(source, Object.class);
-
- ObjectMapper jsonWriter = new ObjectMapper();
-
- workflowSchema.validate(new JSONObject(jsonWriter.writeValueAsString(obj)));
- } else {
- workflowSchema.validate(new JSONObject(source));
- }
- } catch (ValidationException e) {
- e.getCausingExceptions().stream()
- .map(ValidationException::getMessage)
- .forEach(
- m -> {
- if ((!m.equals("#/functions: expected type: JSONObject, found: JSONArray")
- && !m.equals("#/events: expected type: JSONObject, found: JSONArray")
- && !m.equals("#/start: expected type: JSONObject, found: String")
- && !m.equals("#/retries: expected type: JSONObject, found: JSONArray"))) {
- addValidationError(m, ValidationError.SCHEMA_VALIDATION);
- }
- });
- }
+ JsonSchemaFactory.getInstance(VersionFlag.V7)
+ .getSchema(workflowSchema)
+ .validate(Utils.getNode(source))
+ .forEach(m -> addValidationError(m.getMessage(), ValidationError.SCHEMA_VALIDATION));
}
- } catch (Exception e) {
- logger.error("Schema validation exception: " + e.getMessage());
+ } catch (IOException e) {
+ logger.error("Unexpected error during validation", e);
}
}
@@ -101,258 +80,244 @@ public List validate() {
// there is no point of doing the workflow validation
if (validationErrors.size() > 0) {
return validationErrors;
- } else {
- if (workflow == null) {
- workflow = Workflow.fromSource(source);
- }
+ } else if (workflow == null) {
+ workflow = Workflow.fromSource(source);
+ }
- List functions =
- workflow.getFunctions() != null ? workflow.getFunctions().getFunctionDefs() : null;
+ List functions =
+ workflow.getFunctions() != null ? workflow.getFunctions().getFunctionDefs() : null;
- List events =
- workflow.getEvents() != null ? workflow.getEvents().getEventDefs() : null;
+ List events =
+ workflow.getEvents() != null ? workflow.getEvents().getEventDefs() : null;
- if ((workflow.getId() == null || workflow.getId().trim().isEmpty())
- && (workflow.getKey() == null || workflow.getKey().trim().isEmpty())) {
- addValidationError(
- "Workflow id or key should not be empty", ValidationError.WORKFLOW_VALIDATION);
- }
+ if ((workflow.getId() == null || workflow.getId().trim().isEmpty())
+ && (workflow.getKey() == null || workflow.getKey().trim().isEmpty())) {
+ addValidationError(
+ "Workflow id or key should not be empty", ValidationError.WORKFLOW_VALIDATION);
+ }
- if (workflow.getVersion() == null || workflow.getVersion().trim().isEmpty()) {
- addValidationError(
- "Workflow version should not be empty", ValidationError.WORKFLOW_VALIDATION);
- }
+ if (workflow.getVersion() == null || workflow.getVersion().trim().isEmpty()) {
+ addValidationError(
+ "Workflow version should not be empty", ValidationError.WORKFLOW_VALIDATION);
+ }
- if (workflow.getStates() == null || workflow.getStates().isEmpty()) {
- addValidationError("No states found", ValidationError.WORKFLOW_VALIDATION);
- }
+ if (workflow.getStates() == null || workflow.getStates().isEmpty()) {
+ addValidationError("No states found", ValidationError.WORKFLOW_VALIDATION);
+ }
- if (workflow.getStates() != null && !workflow.getStates().isEmpty()) {
- boolean existingStateWithStartProperty = false;
- if (workflow.getStart() != null) {
- String startProperty = workflow.getStart().getStateName();
- for (State s : workflow.getStates()) {
- if (s.getName().equals(startProperty)) {
- existingStateWithStartProperty = true;
- break;
- }
+ if (workflow.getStates() != null && !workflow.getStates().isEmpty()) {
+ boolean existingStateWithStartProperty = false;
+ if (workflow.getStart() != null) {
+ String startProperty = workflow.getStart().getStateName();
+ for (State s : workflow.getStates()) {
+ if (s.getName().equals(startProperty)) {
+ existingStateWithStartProperty = true;
+ break;
}
- } else {
- existingStateWithStartProperty = true;
- }
- if (!existingStateWithStartProperty) {
- addValidationError(
- "No state name found that matches the workflow start definition",
- ValidationError.WORKFLOW_VALIDATION);
}
+ } else {
+ existingStateWithStartProperty = true;
}
+ if (!existingStateWithStartProperty) {
+ addValidationError(
+ "No state name found that matches the workflow start definition",
+ ValidationError.WORKFLOW_VALIDATION);
+ }
+ }
- Validation validation = new Validation();
- if (workflow.getStates() != null && !workflow.getStates().isEmpty()) {
- workflow
- .getStates()
- .forEach(
- s -> {
- if (s.getName() != null && s.getName().trim().isEmpty()) {
- addValidationError(
- "State name should not be empty", ValidationError.WORKFLOW_VALIDATION);
- } else {
- validation.addState(s.getName());
- }
-
- if (s.getEnd() != null) {
- validation.addEndState();
- }
-
- if (s instanceof OperationState) {
- OperationState operationState = (OperationState) s;
-
- List actions = operationState.getActions();
- for (Action action : actions) {
- if (action.getFunctionRef() != null) {
- if (action.getFunctionRef().getRefName().isEmpty()) {
- addValidationError(
- "Operation State action functionRef should not be null or empty",
- ValidationError.WORKFLOW_VALIDATION);
- }
-
- if (!haveFunctionDefinition(
- action.getFunctionRef().getRefName(), functions)) {
- addValidationError(
- "Operation State action functionRef does not reference an existing workflow function definition",
- ValidationError.WORKFLOW_VALIDATION);
- }
+ Validation validation = new Validation();
+ if (workflow.getStates() != null && !workflow.getStates().isEmpty()) {
+ workflow
+ .getStates()
+ .forEach(
+ s -> {
+ if (s.getName() != null && s.getName().trim().isEmpty()) {
+ addValidationError(
+ "State name should not be empty", ValidationError.WORKFLOW_VALIDATION);
+ } else {
+ validation.addState(s.getName());
+ }
+
+ if (s.getEnd() != null) {
+ validation.addEndState();
+ }
+
+ if (s instanceof OperationState) {
+ OperationState operationState = (OperationState) s;
+
+ List actions = operationState.getActions();
+ for (Action action : actions) {
+ if (action.getFunctionRef() != null) {
+ if (action.getFunctionRef().getRefName().isEmpty()) {
+ addValidationError(
+ "Operation State action functionRef should not be null or empty",
+ ValidationError.WORKFLOW_VALIDATION);
}
- if (action.getEventRef() != null) {
- if (action.getEventRef().getTriggerEventRef().isEmpty()) {
- addValidationError(
- "Operation State action trigger eventRef does not reference an existing workflow event definition",
- ValidationError.WORKFLOW_VALIDATION);
- }
-
- if (action.getEventRef().getResultEventRef().isEmpty()) {
- addValidationError(
- "Operation State action results eventRef does not reference an existing workflow event definition",
- ValidationError.WORKFLOW_VALIDATION);
- }
-
- if (!haveEventsDefinition(
- action.getEventRef().getTriggerEventRef(), events)) {
- addValidationError(
- "Operation State action trigger event def does not reference an existing workflow event definition",
- ValidationError.WORKFLOW_VALIDATION);
- }
-
- if (!haveEventsDefinition(
- action.getEventRef().getResultEventRef(), events)) {
- addValidationError(
- "Operation State action results event def does not reference an existing workflow event definition",
- ValidationError.WORKFLOW_VALIDATION);
- }
+ if (!haveFunctionDefinition(
+ action.getFunctionRef().getRefName(), functions)) {
+ addValidationError(
+ "Operation State action functionRef does not reference an existing workflow function definition",
+ ValidationError.WORKFLOW_VALIDATION);
}
}
- }
- if (s instanceof EventState) {
- EventState eventState = (EventState) s;
- if (eventState.getOnEvents() == null || eventState.getOnEvents().size() < 1) {
- addValidationError(
- "Event State has no eventActions defined",
- ValidationError.WORKFLOW_VALIDATION);
- }
- List eventsActionsList = eventState.getOnEvents();
- for (OnEvents onEvents : eventsActionsList) {
+ if (action.getEventRef() != null) {
- List eventRefs = onEvents.getEventRefs();
- if (eventRefs == null || eventRefs.size() < 1) {
+ if (!haveEventsDefinition(
+ action.getEventRef().getTriggerEventRef(), events)) {
addValidationError(
- "Event State eventsActions has no event refs",
+ "Operation State action trigger event def does not reference an existing workflow event definition",
+ ValidationError.WORKFLOW_VALIDATION);
+ }
+
+ if (!haveEventsDefinition(action.getEventRef().getResultEventRef(), events)) {
+ addValidationError(
+ "Operation State action results event def does not reference an existing workflow event definition",
ValidationError.WORKFLOW_VALIDATION);
- } else {
- for (String eventRef : eventRefs) {
- if (!haveEventsDefinition(eventRef, events)) {
- addValidationError(
- "Event State eventsActions eventRef does not match a declared workflow event definition",
- ValidationError.WORKFLOW_VALIDATION);
- }
- }
}
}
}
+ }
- if (s instanceof SwitchState) {
- SwitchState switchState = (SwitchState) s;
- if ((switchState.getDataConditions() == null
- || switchState.getDataConditions().size() < 1)
- && (switchState.getEventConditions() == null
- || switchState.getEventConditions().size() < 1)) {
- addValidationError(
- "Switch state should define either data or event conditions",
- ValidationError.WORKFLOW_VALIDATION);
- }
+ if (s instanceof EventState) {
+ EventState eventState = (EventState) s;
+ if (eventState.getOnEvents() == null || eventState.getOnEvents().size() < 1) {
+ addValidationError(
+ "Event State has no eventActions defined",
+ ValidationError.WORKFLOW_VALIDATION);
+ }
+ List eventsActionsList = eventState.getOnEvents();
+ for (OnEvents onEvents : eventsActionsList) {
- if (switchState.getDefaultCondition() == null) {
+ List eventRefs = onEvents.getEventRefs();
+ if (eventRefs == null || eventRefs.size() < 1) {
addValidationError(
- "Switch state should define a default transition",
+ "Event State eventsActions has no event refs",
ValidationError.WORKFLOW_VALIDATION);
- }
-
- if (switchState.getEventConditions() != null
- && switchState.getEventConditions().size() > 0) {
- List eventConditions = switchState.getEventConditions();
- for (EventCondition ec : eventConditions) {
- if (!haveEventsDefinition(ec.getEventRef(), events)) {
+ } else {
+ for (String eventRef : eventRefs) {
+ if (!haveEventsDefinition(eventRef, events)) {
addValidationError(
- "Switch state event condition eventRef does not reference a defined workflow event",
+ "Event State eventsActions eventRef does not match a declared workflow event definition",
ValidationError.WORKFLOW_VALIDATION);
}
- if (ec.getEnd() != null) {
- validation.addEndState();
- }
}
}
+ }
+ }
+
+ if (s instanceof SwitchState) {
+ SwitchState switchState = (SwitchState) s;
+ if ((switchState.getDataConditions() == null
+ || switchState.getDataConditions().size() < 1)
+ && (switchState.getEventConditions() == null
+ || switchState.getEventConditions().size() < 1)) {
+ addValidationError(
+ "Switch state should define either data or event conditions",
+ ValidationError.WORKFLOW_VALIDATION);
+ }
- if (switchState.getDataConditions() != null
- && switchState.getDataConditions().size() > 0) {
- List dataConditions = switchState.getDataConditions();
- for (DataCondition dc : dataConditions) {
- if (dc.getEnd() != null) {
- validation.addEndState();
- }
+ if (switchState.getDefaultCondition() == null) {
+ addValidationError(
+ "Switch state should define a default transition",
+ ValidationError.WORKFLOW_VALIDATION);
+ }
+
+ if (switchState.getEventConditions() != null
+ && switchState.getEventConditions().size() > 0) {
+ List eventConditions = switchState.getEventConditions();
+ for (EventCondition ec : eventConditions) {
+ if (!haveEventsDefinition(ec.getEventRef(), events)) {
+ addValidationError(
+ "Switch state event condition eventRef does not reference a defined workflow event",
+ ValidationError.WORKFLOW_VALIDATION);
+ }
+ if (ec.getEnd() != null) {
+ validation.addEndState();
}
}
}
- if (s instanceof SleepState) {
- SleepState sleepState = (SleepState) s;
- if (sleepState.getDuration() == null || sleepState.getDuration().length() < 1) {
- addValidationError(
- "Sleep state should have a non-empty time delay",
- ValidationError.WORKFLOW_VALIDATION);
+ if (switchState.getDataConditions() != null
+ && switchState.getDataConditions().size() > 0) {
+ List dataConditions = switchState.getDataConditions();
+ for (DataCondition dc : dataConditions) {
+ if (dc.getEnd() != null) {
+ validation.addEndState();
+ }
}
}
+ }
+
+ if (s instanceof SleepState) {
+ SleepState sleepState = (SleepState) s;
+ if (sleepState.getDuration() == null || sleepState.getDuration().length() < 1) {
+ addValidationError(
+ "Sleep state should have a non-empty time delay",
+ ValidationError.WORKFLOW_VALIDATION);
+ }
+ }
- if (s instanceof ParallelState) {
- ParallelState parallelState = (ParallelState) s;
+ if (s instanceof ParallelState) {
+ ParallelState parallelState = (ParallelState) s;
- if (parallelState.getBranches() == null
- || parallelState.getBranches().size() < 2) {
- addValidationError(
- "Parallel state should have at lest two branches",
- ValidationError.WORKFLOW_VALIDATION);
- }
+ if (parallelState.getBranches() == null
+ || parallelState.getBranches().size() < 2) {
+ addValidationError(
+ "Parallel state should have at lest two branches",
+ ValidationError.WORKFLOW_VALIDATION);
}
+ }
- if (s instanceof InjectState) {
- InjectState injectState = (InjectState) s;
- if (injectState.getData() == null || injectState.getData().isEmpty()) {
- addValidationError(
- "InjectState should have non-null data",
- ValidationError.WORKFLOW_VALIDATION);
- }
+ if (s instanceof InjectState) {
+ InjectState injectState = (InjectState) s;
+ if (injectState.getData() == null || injectState.getData().isEmpty()) {
+ addValidationError(
+ "InjectState should have non-null data",
+ ValidationError.WORKFLOW_VALIDATION);
}
+ }
- if (s instanceof ForEachState) {
- ForEachState forEachState = (ForEachState) s;
- if (forEachState.getInputCollection() == null
- || forEachState.getInputCollection().isEmpty()) {
- addValidationError(
- "ForEach state should have a valid inputCollection",
- ValidationError.WORKFLOW_VALIDATION);
- }
+ if (s instanceof ForEachState) {
+ ForEachState forEachState = (ForEachState) s;
+ if (forEachState.getInputCollection() == null
+ || forEachState.getInputCollection().isEmpty()) {
+ addValidationError(
+ "ForEach state should have a valid inputCollection",
+ ValidationError.WORKFLOW_VALIDATION);
}
+ }
- if (s instanceof CallbackState) {
- CallbackState callbackState = (CallbackState) s;
+ if (s instanceof CallbackState) {
+ CallbackState callbackState = (CallbackState) s;
- if (!haveEventsDefinition(callbackState.getEventRef(), events)) {
- addValidationError(
- "CallbackState event ref does not reference a defined workflow event definition",
- ValidationError.WORKFLOW_VALIDATION);
- }
+ if (!haveEventsDefinition(callbackState.getEventRef(), events)) {
+ addValidationError(
+ "CallbackState event ref does not reference a defined workflow event definition",
+ ValidationError.WORKFLOW_VALIDATION);
+ }
- if (!haveFunctionDefinition(
- callbackState.getAction().getFunctionRef().getRefName(), functions)) {
- addValidationError(
- "CallbackState action function ref does not reference a defined workflow function definition",
- ValidationError.WORKFLOW_VALIDATION);
- }
+ if (!haveFunctionDefinition(
+ callbackState.getAction().getFunctionRef().getRefName(), functions)) {
+ addValidationError(
+ "CallbackState action function ref does not reference a defined workflow function definition",
+ ValidationError.WORKFLOW_VALIDATION);
}
- });
+ }
+ });
- if (validation.endStates == 0) {
- addValidationError("No end state found.", ValidationError.WORKFLOW_VALIDATION);
- }
+ if (validation.endStates == 0) {
+ addValidationError("No end state found.", ValidationError.WORKFLOW_VALIDATION);
}
-
- return validationErrors;
}
+
+ return validationErrors;
}
@Override
public boolean isValid() {
- return validate().size() < 1;
+ return validate().isEmpty();
}
@Override
@@ -381,17 +346,30 @@ private boolean haveFunctionDefinition(String functionName, List events) {
+ if (eventName == null) {
+ return true;
+ }
if (events != null) {
EventDefinition eve =
events.stream().filter(e -> e.getName().equals(eventName)).findFirst().orElse(null);
-
return eve == null ? false : true;
} else {
return false;
}
}
+ private static final Set skipMessages =
+ new HashSet() {
+ {
+ add("$.start: string found, object expected");
+ add("$.functions: array found, object expected");
+ }
+ };
+
private void addValidationError(String message, String type) {
+ if (skipMessages.contains(message)) {
+ return;
+ }
ValidationError mainError = new ValidationError();
mainError.setMessage(message);
mainError.setType(type);
@@ -399,30 +377,9 @@ private void addValidationError(String message, String type) {
}
private class Validation {
-
- final Set events = new HashSet<>();
- final Set functions = new HashSet<>();
final Set states = new HashSet<>();
Integer endStates = 0;
- void addFunction(String name) {
- if (functions.contains(name)) {
- addValidationError(
- "Function does not have an unique name: " + name, ValidationError.WORKFLOW_VALIDATION);
- } else {
- functions.add(name);
- }
- }
-
- void addEvent(String name) {
- if (events.contains(name)) {
- addValidationError(
- "Event does not have an unique name: " + name, ValidationError.WORKFLOW_VALIDATION);
- } else {
- events.add(name);
- }
- }
-
void addState(String name) {
if (states.contains(name)) {
addValidationError(
diff --git a/validation/src/test/java/io/serverlessworkflow/validation/test/WorkflowValidationTest.java b/validation/src/test/java/io/serverlessworkflow/validation/test/WorkflowValidationTest.java
index a81e14f6..08237525 100644
--- a/validation/src/test/java/io/serverlessworkflow/validation/test/WorkflowValidationTest.java
+++ b/validation/src/test/java/io/serverlessworkflow/validation/test/WorkflowValidationTest.java
@@ -15,14 +15,26 @@
*/
package io.serverlessworkflow.validation.test;
+import static io.serverlessworkflow.api.states.DefaultState.Type.OPERATION;
import static io.serverlessworkflow.api.states.DefaultState.Type.SLEEP;
import io.serverlessworkflow.api.Workflow;
+import io.serverlessworkflow.api.actions.Action;
import io.serverlessworkflow.api.end.End;
+import io.serverlessworkflow.api.events.EventDefinition;
+import io.serverlessworkflow.api.events.EventRef;
+import io.serverlessworkflow.api.functions.FunctionDefinition;
+import io.serverlessworkflow.api.functions.FunctionDefinition.Type;
+import io.serverlessworkflow.api.functions.FunctionRef;
import io.serverlessworkflow.api.interfaces.WorkflowValidator;
+import io.serverlessworkflow.api.retry.RetryDefinition;
import io.serverlessworkflow.api.start.Start;
+import io.serverlessworkflow.api.states.OperationState;
import io.serverlessworkflow.api.states.SleepState;
import io.serverlessworkflow.api.validation.ValidationError;
+import io.serverlessworkflow.api.workflow.Events;
+import io.serverlessworkflow.api.workflow.Functions;
+import io.serverlessworkflow.api.workflow.Retries;
import io.serverlessworkflow.validation.WorkflowValidatorImpl;
import java.util.Arrays;
import java.util.List;
@@ -46,8 +58,7 @@ public void testIncompleteYamlWithSchemaValidation() {
List validationErrors =
workflowValidator.setSource("---\n" + "key: abc\n").validate();
Assertions.assertNotNull(validationErrors);
- System.out.println(validationErrors);
- Assertions.assertEquals(3, validationErrors.size());
+ Assertions.assertEquals(4, validationErrors.size());
}
@Test
@@ -108,11 +119,10 @@ public void testWorkflowMissingStatesIdAndKey() {
+ "}")
.validate();
Assertions.assertNotNull(validationErrors);
- Assertions.assertEquals(2, validationErrors.size());
+ Assertions.assertEquals(1, validationErrors.size());
Assertions.assertEquals(
- "Workflow id or key should not be empty", validationErrors.get(0).getMessage());
- Assertions.assertEquals("No states found", validationErrors.get(1).getMessage());
+ "$.id: is missing but it is required", validationErrors.get(0).getMessage());
}
@Test
@@ -162,7 +172,6 @@ public void testOperationStateNoFunctionRef() {
Assertions.assertNotNull(validationErrors);
Assertions.assertEquals(1, validationErrors.size());
- // validationErrors.stream().forEach(v -> System.out.println(v.toString()));
Assertions.assertEquals(
"Operation State action functionRef does not reference an existing workflow function definition",
validationErrors.get(0).getMessage());
@@ -280,4 +289,48 @@ public void testMissingFunctionRefForCallbackState() {
"CallbackState action function ref does not reference a defined workflow function definition",
validationErrors.get(1).getMessage());
}
+
+ @Test
+ void testFunctionCall() {
+ Workflow workflow =
+ new Workflow()
+ .withId("test-workflow")
+ .withVersion("1.0")
+ .withStart(new Start().withStateName("start"))
+ .withFunctions(
+ new Functions(
+ Arrays.asList(new FunctionDefinition("expression").withType(Type.EXPRESSION))))
+ .withStates(
+ Arrays.asList(
+ new OperationState()
+ .withName("start")
+ .withType(OPERATION)
+ .withActions(
+ Arrays.asList(
+ new Action().withFunctionRef(new FunctionRef("expression"))))
+ .withEnd(new End())));
+ Assertions.assertTrue(new WorkflowValidatorImpl().setWorkflow(workflow).validate().isEmpty());
+ }
+
+ @Test
+ void testEventCall() {
+ Workflow workflow =
+ new Workflow()
+ .withId("test-workflow")
+ .withVersion("1.0")
+ .withStart(new Start().withStateName("start"))
+ .withEvents(new Events(Arrays.asList(new EventDefinition().withName("event"))))
+ .withRetries(new Retries(Arrays.asList(new RetryDefinition("start", "PT1S"))))
+ .withStates(
+ Arrays.asList(
+ new OperationState()
+ .withName("start")
+ .withType(OPERATION)
+ .withActions(
+ Arrays.asList(
+ new Action()
+ .withEventRef(new EventRef().withTriggerEventRef("event"))))
+ .withEnd(new End())));
+ Assertions.assertTrue(new WorkflowValidatorImpl().setWorkflow(workflow).validate().isEmpty());
+ }
}