yWorkflow Documentation

Add yWorkflow dependencies

val yworkflowVersion = "..."

dependencies {
    implementation(platform("com.yworkflow:yworkflow-bom:$yworkflowVersion")) (1)
    implementation("com.yworkflow:yworkflow-engine") (2)
    implementation("com.yworkflow:definition-factory-yaml") (3)
}
1 Import the yWorkflow Bill of Materials (BOM) to manage all module versions centrally.
2 Include the core workflowDefinition engine.
3 Add support for defining workflowEngine using YAML files.

Initialize the workflowDefinition engine

QuickstartWorkflowTest.java
var extensions = new InMemoryExtensionProvider(); (1)
extensions.register(new JoinStatesStatusCondition());
extensions.register(new IsUserOwnerCondition());
extensions.register(new TransitionInputValidator());
extensions.register(new PersistInputAttributeFunction());

var instanceStore = new InMemoryWorkflowInstanceStore(); (2)

var workflowEngine = WorkflowEngine.builder()
        .withInstanceStore(instanceStore)
        .withExtensions(extensions)
        .build(); (3)
1 create a InMemoryExtensionProvider and register all extensions (conditions, functions, etc.) the workflowDefinition uses (i.e. every alias found in the workflowDefinition will be looked up using this object).
2 create a store that holds workflowDefinition instances in memory
3 Use builder to create a WorkflowEngine instance

Define the workflowDefinition using YAML

Expand to see the workflowDefinition state diagram.

leave request state diagram

leave_request.yml
workflow:
  id: "leave_request"
  initial-transitions:
    - id: "create"
      name: "Create Leave Request Draft"
      validators:
        - alias: "validate.input"
          args:
            - name: "from"
            - format: "^\\d{4}-\\d{2}-\\d{2}$"
        - alias: "validate.input"
          args:
            - name: "to"
            - format: "^\\d{4}-\\d{2}-\\d{2}$"
            - required: true
      post-functions:
        - alias: "persist.input"
          args:
            - name: "from"
        - alias: "persist.input"
          args:
            - name: "to"
      default-result:
        state: "draft_leave_request"
  states:
    - id: "draft_leave_request"
      name: "Draft Leave Request"
      transitions:
        - id: "submit"
          name: "Submit Leave Request"
          default-result:
            fork: "forward_to_approvers"
    - id: "manager_approval"
      name: "Manager Approval"
      transitions:
        - id: "manager_deny"
          name: "Manager Deny Request"
          guards:
            - alias: "check.state.owner"
          default-result:
            state: "draft_leave_request"
            exit-status: "rejected"
        - id: "manager_approve"
          name: "Manager Approve Request"
          guards:
            - alias: "check.state.owner"
          default-result:
            join: "check_everybody_approved"
    - id: "hr_approval"
      name: "HR approval"
      transitions:
        - id: "hr_deny"
          name: "HR deny request"
          guards:
            - alias: "check.state.owner"
          default-result:
            state: "draft_leave_request"
            exit-status: "rejected"
        - id: "hr_approve"
          name: "HR approve request"
          guards:
            - alias: "check.state.owner"
          default-result:
            join: "check_everybody_approved"
    - id: "approved"
      name: "Leave request approved"
  forks:
    - id: "forward_to_approvers"
      default-results:
        - state: "manager_approval"
          owners:
            - "manager"
        - state: "hr_approval"
          owners:
            - "hr"
  joins:
    - id: "check_everybody_approved"
      condition:
        - alias: "check.join.states.status"
      default-result:
        state: "approved"

Load the YAML workflowDefinition file

QuickstartWorkflowTest.java
var workflowYamlString = loadFileAsString("leave_request.yml"); (1)
var definitionSource = WorkflowYaml.fromYamlString(workflowYamlString);
var workflowDefinition = definitionSource.toWorkflowDefinition(); (2)
workflowEngine.definitions().save(workflowDefinition); (3)
1 load YAML file content
2 convert YAML to WorkflowDefinition definition
3 save Workflow definition

Create instance of the workflowDefinition

QuickstartWorkflowTest.java
var inputs = mutableAttributes()
        .withString("from", "2024-01-01")
        .withString("to", "2024-01-07")
        .toImmutable();

var workflowDefinitionId = workflowDefinitionId("leave_request");
var transitionId = transitionId("create");

var leaveRequest = workflowEngine.instances().init(workflowDefinitionId, transitionId, inputs);

assertThat(leaveRequest).hasAvailableTransitions("submit");
assertThat(leaveRequest).hasStatus(WorkflowInstanceStatus.STARTED);

Submit Leave Request

QuickstartWorkflowTest.java
leaveRequest.transition(transitionId("submit"));
assertThat(leaveRequest).hasNoAvailableTransitions();

Approve as manager

QuickstartWorkflowTest.java
var leaveRequestAsManager = leaveRequest.actAs(caller("manager"));
assertThat(leaveRequestAsManager).hasAvailableTransitions("manager_deny", "manager_approve");
leaveRequestAsManager.transition(transitionId("manager_approve"));

Approve as HR

QuickstartWorkflowTest.java
var leaveRequestAsHr = leaveRequest.actAs(caller("hr"));

assertThat(leaveRequestAsHr).hasAvailableTransitions("hr_deny", "hr_approve");

leaveRequestAsHr.transition(transitionId("hr_approve"));

Assert workflowDefinition state

assertThat(leaveRequest).hasStatus(WorkflowInstanceStatus.COMPLETED); (1)

assertThat(leaveRequest).hasNoAvailableTransitions(); (2)

assertThat(leaveRequest).hasAttribute("from", "2024-01-01"); (3)
assertThat(leaveRequest).hasAttribute("to", "2024-01-07");
1 once both HR and Manager approved the leave request, the workflowDefinition is in completed state
2 no more transitions are available at this point
3 inputs were persisted as workflowDefinition attributes