Skip to content

Commit a2bf7a2

Browse files
author
Tihomir Surdilovic
committed
Add Workflow validation
Signed-off-by: Tihomir Surdilovic <[email protected]>
1 parent f358295 commit a2bf7a2

File tree

28 files changed

+984
-387
lines changed

28 files changed

+984
-387
lines changed

README.md

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,15 @@
33

44
# Serverless Workflow Specification - Java SDK
55

6-
Provides the Java API/SPI for the [Serverless Workflow Specification](https://github.com/serverlessworkflow/specification)
6+
Provides the Java API/SPI and Model Validation for the [Serverless Workflow Specification](https://github.com/serverlessworkflow/specification)
77

8-
Allows you to parse Workflow types from JSON/YAML sources, as well as programmatically build your workflows using
9-
the provided builder API.
8+
With the SDK you can:
9+
* Parse workflow JSON and YAML definitions
10+
* Programatically build workflow definitions
11+
* Validate workflow definitions (both schema and workflow integrity validation)
1012

11-
The SDK focus is to allow to quickly go from the workflow definition (JSON or YAML) to instances
12-
of Workflow type, as well as to provide a builder API to easily create a workflow programmatically.
13-
14-
Future versions will also include validation functionality.
15-
16-
This is **not** a workflow runtime implementation.
13+
Serverless Workflow Java SDK is **not** a workflow runtime implementation but can be used by Java runtime implementations
14+
to parse and validate workflow definitions.
1715

1816
### Status
1917

@@ -54,6 +52,16 @@ Then to use it in your project pom.xml add:
5452
</dependency>
5553
```
5654

55+
* Validation dependency
56+
57+
```xml
58+
<dependency>
59+
<groupId>io.serverlessworkflow</groupId>
60+
<artifactId>serverlessworkflow-validation</artifactId>
61+
<version>0.2-SNAPSHOT</version>
62+
</dependency>
63+
```
64+
5765
#### Get dependencies from Nexus
5866

5967
Our SNAPSHOT versions are published to the Sonatype repositories.
@@ -83,8 +91,6 @@ And use the dependencies:
8391
</dependency>
8492
```
8593

86-
and
87-
8894
```xml
8995
<dependency>
9096
<groupId>io.serverlessworkflow</groupId>
@@ -93,6 +99,14 @@ and
9399
</dependency>
94100
```
95101

102+
```xml
103+
<dependency>
104+
<groupId>io.serverlessworkflow</groupId>
105+
<artifactId>serverlessworkflow-validation</artifactId>
106+
<version>0.2-SNAPSHOT</version>
107+
</dependency>
108+
```
109+
96110
### How to Use
97111

98112
#### Creating from JSON/YAML source
@@ -170,7 +184,7 @@ Workflow testWorkflow = new Workflow().withId("test-workflow").withName("test-wo
170184
new EventDefinition().withName("testEvent").withSource("testSource").withType("testType"))
171185
)
172186
.withFunctions(Arrays.asList(
173-
new Function().withName("testFunction").withResource("testResource").withType("testType"))
187+
new FunctionDefinition().withName("testFunction").withResource("testResource").withType("testType"))
174188
)
175189
.withStates(Arrays.asList(
176190
new DelayState().withName("delayState").withType(DELAY)
@@ -193,3 +207,44 @@ You can use the workflow instance to get its JSON/YAML definition as well:
193207
assertNotNull(Workflow.toJson(testWorkflow));
194208
assertNotNull(Workflow.toYaml(testWorkflow));
195209
```
210+
211+
#### Using Workflow Validation
212+
213+
Validation allows you to performe Json Schema validation against the JSON/YAML workflow definitions.
214+
Once you have a `Workflow` instance, you can also run integrity checks.
215+
216+
You can validate a Workflow JSON/YAML definition to get validation errors:
217+
218+
``` java
219+
WorkflowValidator workflowValidator = new WorkflowValidatorImpl();
220+
List<ValidationError> validationErrors = workflowValidator.setSource("WORKFLOW_MODEL_JSON/YAML").validate();
221+
```
222+
223+
Where `WORKFLOW_MODEL_JSON/YAML` is the actual workflow model JSON or YAML definition.
224+
225+
Or you can just check if it is valid (without getting specific errors):
226+
227+
``` java
228+
WorkflowValidator workflowValidator = new WorkflowValidatorImpl();
229+
boolean isValidWorkflow = workflowValidator.setSource("WORKFLOW_MODEL_JSON/YAML").isValid();
230+
```
231+
232+
If you build your Workflow programmatically, you can validate it as well:
233+
234+
``` java
235+
Workflow workflow = new Workflow().withId("test-workflow").withVersion("1.0")
236+
.withStates(Arrays.asList(
237+
new DelayState().withName("delayState").withType(DELAY)
238+
.withStart(
239+
new Start().withKind(Start.Kind.DEFAULT)
240+
)
241+
.withEnd(
242+
new End().withKind(End.Kind.DEFAULT)
243+
)
244+
.withTimeDelay("PT1M")
245+
)
246+
);
247+
248+
WorkflowValidator workflowValidator = new WorkflowValidatorImpl();
249+
List<ValidationError> validationErrors = workflowValidator.setWorkflow(workflow).validate();
250+
```

api/pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@
3434
<groupId>javax.validation</groupId>
3535
<artifactId>validation-api</artifactId>
3636
</dependency>
37+
<dependency>
38+
<groupId>org.json</groupId>
39+
<artifactId>json</artifactId>
40+
</dependency>
41+
<dependency>
42+
<groupId>com.github.everit-org.json-schema</groupId>
43+
<artifactId>org.everit.json.schema</artifactId>
44+
</dependency>
3745

3846
<!-- test -->
3947
<dependency>

api/src/main/java/io/serverlessworkflow/api/interfaces/ExpressionEvaluator.java

Lines changed: 0 additions & 27 deletions
This file was deleted.

api/src/main/java/io/serverlessworkflow/api/interfaces/WorkflowManager.java

Lines changed: 0 additions & 48 deletions
This file was deleted.

api/src/main/java/io/serverlessworkflow/api/interfaces/WorkflowValidator.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,22 @@
1616
*/
1717
package io.serverlessworkflow.api.interfaces;
1818

19-
public interface WorkflowValidator {
19+
import io.serverlessworkflow.api.Workflow;
20+
import io.serverlessworkflow.api.validation.ValidationError;
2021

21-
WorkflowValidator setWorkflowManager(WorkflowManager workflowManager);
22+
import java.util.List;
2223

23-
void setJson(String json);
24+
public interface WorkflowValidator {
2425

25-
void setYaml(String yaml);
26+
WorkflowValidator setWorkflow(Workflow workflow);
2627

27-
boolean isValid();
28+
WorkflowValidator setSource(String source);
2829

29-
void setEnabled(boolean enabled);
30+
List<ValidationError> validate();
3031

31-
void setSchemaValidationEnabled(boolean schemaValidationEnabled);
32+
boolean isValid();
3233

33-
void setStrictValidationEnabled(boolean strictValidationEnabled);
34+
WorkflowValidator setSchemaValidationEnabled(boolean schemaValidationEnabled);
3435

35-
void reset();
36+
WorkflowValidator reset();
3637
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
package io.serverlessworkflow.api.schemaclient;
18+
19+
import org.everit.json.schema.loader.SchemaClient;
20+
21+
import java.io.InputStream;
22+
import java.util.Objects;
23+
24+
public class ResourceSchemaClient implements SchemaClient {
25+
26+
private final SchemaClient fallbackClient;
27+
private final String baseResourcePath = "/schema/";
28+
29+
public ResourceSchemaClient(SchemaClient fallbackClient) {
30+
this.fallbackClient = Objects.requireNonNull(fallbackClient,
31+
"fallbackClient cannot be null");
32+
}
33+
34+
public InputStream get(String path) {
35+
path = path.substring("https://wg-serverless.org/".length());
36+
return this.getClass().getResourceAsStream(baseResourcePath + path);
37+
}
38+
}

api/src/main/java/io/serverlessworkflow/api/serializers/WorkflowSerializer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
2222
import io.serverlessworkflow.api.Workflow;
2323
import io.serverlessworkflow.api.events.EventDefinition;
24-
import io.serverlessworkflow.api.functions.Function;
24+
import io.serverlessworkflow.api.functions.FunctionDefinition;
2525
import io.serverlessworkflow.api.interfaces.Extension;
2626
import io.serverlessworkflow.api.interfaces.State;
2727

@@ -102,7 +102,7 @@ public void serialize(Workflow workflow,
102102

103103
if (workflow.getFunctions() != null && !workflow.getFunctions().isEmpty()) {
104104
gen.writeArrayFieldStart("functions");
105-
for (Function function : workflow.getFunctions()) {
105+
for (FunctionDefinition function : workflow.getFunctions()) {
106106
gen.writeObject(function);
107107
}
108108
gen.writeEndArray();
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
package io.serverlessworkflow.api.validation;
18+
19+
public class ValidationError {
20+
private static final String MSG_FORMAT = "%s:%s";
21+
public static final String SCHEMA_VALIDATION = "schemavalidation";
22+
public static final String WORKFLOW_VALIDATION = "workflowvalidation";
23+
24+
private String message;
25+
private String type;
26+
27+
public String getMessage() {
28+
return message;
29+
}
30+
31+
public void setMessage(String message) {
32+
this.message = message;
33+
}
34+
35+
public String getType() {
36+
return type;
37+
}
38+
39+
public void setType(String type) {
40+
this.type = type;
41+
}
42+
43+
@Override
44+
public String toString() {
45+
return String.format(MSG_FORMAT,
46+
type,
47+
message);
48+
}
49+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
package io.serverlessworkflow.api.validation;
18+
19+
import io.serverlessworkflow.api.schemaclient.ResourceSchemaClient;
20+
import org.everit.json.schema.Schema;
21+
import org.everit.json.schema.loader.SchemaLoader;
22+
import org.everit.json.schema.loader.internal.DefaultSchemaClient;
23+
import org.json.JSONObject;
24+
import org.json.JSONTokener;
25+
26+
public class WorkflowSchemaLoader {
27+
private static final JSONObject workflowSchema = new JSONObject(new JSONTokener(
28+
WorkflowSchemaLoader.class.getResourceAsStream("/schema/workflow.json")));
29+
30+
public static Schema getWorkflowSchema() {
31+
SchemaLoader schemaLoader = SchemaLoader.builder()
32+
.schemaClient(new ResourceSchemaClient(new DefaultSchemaClient()))
33+
.schemaJson(workflowSchema)
34+
.resolutionScope("classpath:schema")
35+
.draftV7Support()
36+
.build();
37+
return schemaLoader.load().build();
38+
}
39+
}

0 commit comments

Comments
 (0)