Finding documentation for old versions of libraries (feat. Flowable)

The Context

On my current project, I’m working on a Groovy on Grails application which uses Axon Framework to create an event sourcing architecture and Flowable version 6.4.1 to control workflows of users as they move from task to task.
A workflow (or process definition) is a flow diagram through which a piece of work can progress from one stage (activity) to the next. When the piece of work progresses to the next activity, a task is created - task progression can trigger multiple tasks to be create in parallel tracks as seen in the diagram below.
notion image
The flow diagrams are created in a visual BPMN diagram editor and is exported to XML to define the tasks that can occur in a process and how they link to one-another.

The Problem

We wanted to fire an event when a task is ready to complete, which is when the task is created in an activity. We decided not to fire an event on task completion while targeting the following/next task due to the complexity of the graph traversal. This complexity is supposed to be handled by Flowable.
Our version of flowable is 6.4.1 - in 6.5 the API was updated to change how event listeners can be registered for when the flowable library creates a task, and all the docs for the old version had been removed from the web.
We found the flowable Java docs for a TaskListener interface, however there is no accompanying documentation on how to implement and some of the links in the Java docs were broken.
We knew that there must be a way to implement the TaskListener, however with no reference, it seemed like there wasn’t a better way than guessing.

The Solution

We jumped into the source code on GitHub to see if there were any clues on how it could be implemented. We looked in the source code and checked out to the release branch for 6.4.1 and then did a global search for TaskListener. We found occurrences in .adoc files, which lived in the /docs directory - we had found the old documentation!
From reading the docs, it looks like we have 2 options:
  1. Generic event handler (read from [[eventDispatcher]] down), which lives on the process definitions (i.e. one for the whole BPMN)
  1. Task Listener (read from [[taskListeners]] down), which lives on each the userTask definition.
Once we slowed down and read through the relevant docs, the options seemed much clearer.

The Code

<process id="testEventListeners"> <extensionElements> <flowable:eventListener class="org.flowable.engine.test.MyEventListener" entityType="task" /> <flowable:eventListener delegateExpression="${testEventListener}" events="TASK_ASSIGNED" entityType="task" /> </extensionElements> ... </process>

Event Listener

public class MyEventListener implements FlowableEventListener { @Override public void onEvent(FlowableEvent event) { if(event.getType() == FlowableEngineEventType.JOB_EXECUTION_SUCCESS) { System.out.println("A job well done!"); } else if (event.getType() == FlowableEngineEventType.JOB_EXECUTION_FAILURE) { System.out.println("A job has failed..."); } else { System.out.println("Event received: " + event.getType()); } } @Override public boolean isFailOnException() { // The logic in the onEvent method of this listener is not critical, exceptions // can be ignored if logging fails... return false; } @Override public boolean isFireOnTransactionLifecycleEvent() { return false; } @Override public String getOnTransaction() { return null; } }

Task Listener

<process id="testEventListeners"> <userTask id="myTask" name="My Task" > <extensionElements> <flowable:taskListener event="create" class="org.flowable.MyTaskCreateListener" /> </extensionElements> </userTask> </process>
public class MyTaskCreateListener implements TaskListener { public void notify(DelegateTask delegateTask) { // Custom logic goes here } }