Provides the Java API/SPI and Model Validation for the Serverless Workflow Specification
With the SDK you can:
- Parse workflow JSON and YAML definitions
- Programmatically build workflow definitions
- Validate workflow definitions (both schema and workflow integrity validation)
- Generate workflow diagram (SVG)
- Set of utilities to help runtimes interpret the Serverless Workflow object model
Serverless Workflow Java SDK is not a workflow runtime implementation but can be used by Java runtime implementations to parse and validate workflow definitions as well as generate the workflow diagram (SVG).
Latest Releases | Conformance to spec version |
---|---|
4.0.4.Final | v0.8 |
4.0.3.Final | v0.8 |
3.0.0.Final | v0.7 |
2.0.0.Final | v0.6 |
1.0.3.Final | v0.5 |
SDK Version | JDK Version |
---|---|
5.0.0 and after | 11 |
4.0.x and before | 8 |
See instructions how to define dependencies for the latest SDK release for both Maven and Gradle here.
To build project and run tests locally:
git clone https://github.com/serverlessworkflow/sdk-java.git
mvn clean install
The project uses Google's code styleguide. Your changes should be automatically formatted during the build.
a) Add the following repository to your pom.xml repositories
section:
<repository>
<id>oss.sonatype.org-snapshot</id>
<url>http://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
b) Add the following dependencies to your pom.xml dependencies
section:
<dependency>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-api</artifactId>
<version>5.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-spi</artifactId>
<version>5.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-validation</artifactId>
<version>5.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-diagram</artifactId>
<version>5.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-util</artifactId>
<version>5.0.0-SNAPSHOT</version>
</dependency>
a) Add the following repositories to your build.gradle repositories
section:
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
b) Add the following dependencies to your build.gradle dependencies
section:
implementation("io.serverlessworkflow:serverlessworkflow-api:5.0.0-SNAPSHOT")
implementation("io.serverlessworkflow:serverlessworkflow-spi:5.0.0-SNAPSHOT")
implementation("io.serverlessworkflow:serverlessworkflow-validation:5.0.0-SNAPSHOT")
implementation("io.serverlessworkflow:serverlessworkflow-diagram:5.0.0-SNAPSHOT")
implementation("io.serverlessworkflow:serverlessworkflow-util:5.0.0-SNAPSHOT")
You can create a Workflow instance from JSON/YAML source:
Let's say you have a simple YAML based workflow definition:
id: greeting
version: '1.0'
name: Greeting Workflow
start: Greet
description: Greet Someone
functions:
- name: greetingFunction
operation: file://myapis/greetingapis.json#greeting
states:
- name: Greet
type: operation
actions:
- functionRef:
refName: greetingFunction
arguments:
name: "${ .greet.name }"
actionDataFilter:
results: "${ .payload.greeting }"
stateDataFilter:
output: "${ .greeting }"
end: true
To parse it and create a Workflow instance you can do:
Workflow workflow = Workflow.fromSource(source);
where 'source' is the above mentioned YAML definition.
The fromSource static method can take in definitions in both JSON and YAML formats.
Once you have the Workflow instance you can use its API to inspect it, for example:
assertNotNull(workflow);
assertEquals("greeting", workflow.getId());
assertEquals("Greeting Workflow", workflow.getName());
assertNotNull(workflow.getFunctions());
assertEquals(1, workflow.getFunctions().size());
assertEquals("greetingFunction", workflow.getFunctions().get(0).getName());
assertNotNull(workflow.getStates());
assertEquals(1, workflow.getStates().size());
assertTrue(workflow.getStates().get(0) instanceof OperationState);
OperationState operationState = (OperationState) workflow.getStates().get(0);
assertEquals("Greet", operationState.getName());
assertEquals(DefaultState.Type.OPERATION, operationState.getType());
...
You can also programmatically create Workflow instances, for example:
Workflow workflow = new Workflow()
.withId("test-workflow")
.withName("test-workflow-name")
.withVersion("1.0")
.withStart(new Start().withStateName("MyDelayState"))
.withFunctions(new Functions(Arrays.asList(
new FunctionDefinition().withName("testFunction")
.withOperation("testSwaggerDef#testOperationId")))
)
.withStates(Arrays.asList(
new DelayState().withName("MyDelayState").withType(DELAY)
.withTimeDelay("PT1M")
.withEnd(
new End().withTerminate(true)
)
)
);
This will create a test workflow that defines an event, a function and a single Delay State.
You can use the workflow instance to get its JSON/YAML definition as well:
assertNotNull(Workflow.toJson(testWorkflow));
assertNotNull(Workflow.toYaml(testWorkflow));
Validation allows you to perform Json Schema validation against the JSON/YAML workflow definitions.
Once you have a Workflow
instance, you can also run integrity checks.
You can validate a Workflow JSON/YAML definition to get validation errors:
WorkflowValidator workflowValidator = new WorkflowValidatorImpl();
List<ValidationError> validationErrors = workflowValidator.setSource("WORKFLOW_MODEL_JSON/YAML").validate();
Where WORKFLOW_MODEL_JSON/YAML
is the actual workflow model JSON or YAML definition.
Or you can just check if it is valid (without getting specific errors):
WorkflowValidator workflowValidator = new WorkflowValidatorImpl();
boolean isValidWorkflow = workflowValidator.setSource("WORKFLOW_MODEL_JSON/YAML").isValid();
If you build your Workflow programmatically, you can validate it as well:
Workflow workflow = new Workflow()
.withId("test-workflow")
.withVersion("1.0")
.withStart(new Start().withStateName("MyDelayState"))
.withStates(Arrays.asList(
new DelayState().withName("MyDelayState").withType(DefaultState.Type.DELAY)
.withTimeDelay("PT1M")
.withEnd(
new End().withTerminate(true)
)
));
);
WorkflowValidator workflowValidator = new WorkflowValidatorImpl();
List<ValidationError> validationErrors = workflowValidator.setWorkflow(workflow).validate();
Given a valid workflow definition (JSON/YAML) or a Workflow object you can build the workflow diagram SVG. The generated diagram SVG uses PlantUML state diagram visualization and can be embedded inside your tooling or web pages, or any SVG viewer.
You can build the workflow diagram SVG with the following code:
Workflow workflow = Workflow.fromSource(source);
WorkflowDiagram workflowDiagram = new WorkflowDiagramImpl();
workflowDiagram.setWorkflow(workflow);
String diagramSVG = workflowDiagram.getSvgDiagram();
diagramSVG
includes the diagram SVG source which you can then decide to save to a file,
print, or process further.
In case default visualization of the workflow is not sufficient you can provide custom workflow template to be used while generating the SVG file. Easiest is to start off from the default template and customize it to your needs.
Custom template must be on the classpath in templates/plantuml
directory and must use .txt
extension. Next
template is set on WorkflowDiagram
instance as shown below.
Workflow workflow = Workflow.fromSource(source);
WorkflowDiagram workflowDiagram = new WorkflowDiagramImpl();
workflowDiagram.setWorkflow(workflow);
workflowDiagram.setTemplate("custom-template");
String diagramSVG = workflowDiagram.getSvgDiagram();
By default the diagram legend is now shown. If you want to enable it you can do:
Workflow workflow = Workflow.fromSource(source);
WorkflowDiagram workflowDiagram = new WorkflowDiagramImpl();
workflowDiagram.setWorkflow(workflow)
.showLegend(true);
String diagramSVG = workflowDiagram.getSvgDiagram();
Here are some generated diagrams from the specification examples (with legend enabled):
Workflow utils provide a number of useful methods for extracting information from workflow definitions.
Once you have a Workflow
instance, you can use it
State startingState = WorkflowUtils.getStartingState(workflow);
List<State> states = WorkflowUtils.getStates(workflow, DefaultState.Type.EVENT);
List<EventDefinition> consumedEvents = WorkflowUtils.getWorkflowConsumedEvents(workflow);
int consumedEventsCount = WorkflowUtils.getWorkflowConsumedEventsCount(workflow);
List<EventDefinition> producedEvents = WorkflowUtils.getWorkflowProducedEvents(workflow);
int producedEventsCount = WorkflowUtils.getWorkflowProducedEventsCount(workflow);
List<EventDefinition> consumedEvents = WorkflowUtils.getWorkflowConsumedEventsCount(workflow);
int consumedEventsCount = WorkflowUtils.getWorkflowConsumedEventsCount(workflow);
List<EventDefinition> producedEvents = WorkflowUtils.getWorkflowProducedEvents(workflow);
int producedEventsCount = WorkflowUtils.getWorkflowProducedEventsCount(workflow);
FunctionDefinition finalizeApplicationFunctionDefinition =
WorkflowUtils.getFunctionDefinitionsForAction(workflow, "finalizeApplicationAction");
List<Action> actionsForFunctionDefinition =
WorkflowUtils.getActionsForFunctionDefinition(workflow, functionRefName);
SDK includes extra functionalities which are not part of core modules but are very useful and can be used as addons to the core:
This is a Spring Boot app which builds a rest api for diagram generation. It was contributed by our community member David Marques.
To start using it:
cd diagram-rest
mvn clean install spring-boot:run
Then you can get the diagram SVG for a workflow definition for example:
curl -X POST localhost:8090/diagram -d '{"id":"booklending","name":"Book Lending Workflow","version":"1.0","specVersion":"0.8","start":"Book Lending Request","states":[{"name":"Book Lending Request","type":"event","onEvents":[{"eventRefs":["Book Lending Request Event"]}],"transition":"Get Book Status"},{"name":"Get Book Status","type":"operation","actions":[{"functionRef":{"refName":"Get status for book","arguments":{"bookid":"${ .book.id }"}}}],"transition":"Book Status Decision"},{"name":"Book Status Decision","type":"switch","dataConditions":[{"name":"Book is on loan","condition":"${ .book.status == \"onloan\" }","transition":"Report Status To Lender"},{"name":"Check is available","condition":"${ .book.status == \"available\" }","transition":"Check Out Book"}]},{"name":"Report Status To Lender","type":"operation","actions":[{"functionRef":{"refName":"Send status to lender","arguments":{"bookid":"${ .book.id }","message":"Book ${ .book.title } is already on loan"}}}],"transition":"Wait for Lender response"},{"name":"Wait for Lender response","type":"switch","eventConditions":[{"name":"Hold Book","eventRef":"Hold Book Event","transition":"Request Hold"},{"name":"Decline Book Hold","eventRef":"Decline Hold Event","transition":"Cancel Request"}]},{"name":"Request Hold","type":"operation","actions":[{"functionRef":{"refName":"Request hold for lender","arguments":{"bookid":"${ .book.id }","lender":"${ .lender }"}}}],"transition":"Wait two weeks"},{"name":"Wait two weeks","type":"sleep","duration":"P2W","transition":"Get Book Status"},{"name":"Check Out Book","type":"operation","actions":[{"functionRef":{"refName":"Check out book with id","arguments":{"bookid":"${ .book.id }"}}},{"functionRef":{"refName":"Notify Lender for checkout","arguments":{"bookid":"${ .book.id }","lender":"${ .lender }"}}}],"end":true}],"functions":[],"events":[]}'