Kogito User Task Process API

It can be argued that the greatest technical advances in the history of humankind (agriculture, wheel, steam machine, printing…) have augmented production while reducing human effort. This does not imply that these advances have removed human intervention altogether. On the contrary, they have allowed humans to focus on the most relevant parts of the production process, those places where human genius can make a difference. In agriculture, humans are pivotal in the discovery of new breeds; wheeled vehicles propelled by steam machines derivatives still need human drivers to reach their intended destination and printers will be useless without authors willing to write books.

Kogito is not an exception. Although the BPMN ecosystem is all about the pursuit of automation, there is still much needed room for direct human intervention in most business processes. Aware of that circumstance, BPMN contributors defined User Task activity:

“A User Task is a typical “workflow” Task where a human performer performs the Task with the assistance of a software application and is scheduled through a task list manager of some sort”. BPMN Specification

A User Task in Kogito is also known as a Human Task. I will be using both terms indistinguishably. This is the first post of a series where I will be discussing Kogito functionality related with User Task. In this one, I will focus on the process API. 

User/Human Tasks

A Human Task might be considered a state machine, with at least one initial and one final state. A Human Task might also be viewed as a function, because given a set of inputs it will produce a set of results. 

The life cycle of Human Task typically consists of a sequence of phases, starting with an Active phase, which every created task is initialized to, and finishing with a Complete phase. Between these initial and final states, a Task can go through an arbitrary number of phases, including no phase at all between Active and Complete. The fact that there is an arbitrary number of phases is an important difference from jBPM, where all possible transitions were predefined and immutable, while in Kogito it is up to the final user to decide which transitions are valid, by creating its own custom phases.

A User Task can also be interpreted as a human function, where a human, after looking at the input parameters, might add additional information in the form of output parameters or results.  The set of key value pairs that might act as input to the task or be a result of the task completion is known as the Task Model. In Kogito, the Task Model is predefined and generated as part of the compilation of the  process definition.

One consequence of what was stated in the previous paragraph is that a human cannot  add more information to the task model without changing process definition. The exception to that rule are comments and attachments: 

  • A comment consists of a human readable text that will help to achieve a successful resolution of the task. 
  • An attachment is a reference to an external URIs containing information relevant to the task, for example a screen snapshot. 

Note the way attachments are implemented in Kogito is completely  different from the approach taken in jBPM. In jBPM, attachment content was expected to be stored, while in Kogito, just the URI reference is saved.

When during process execution, a User Task node is reached, relevant process properties are passed as input parameters to the task and  the process is paused till the task is completed through human intervention. Once the task reaches its Complete phase, results produced by that task are mapped to process properties and the process execution resumes.

Kogito Runtime Task API

Once a task becomes active, it has to be eventually completed to resume the process that instantiates it. Therefore, users should be able to change the current task phase, update tasks results or perform both operations at the same time. They should  also be able to manage comments and attachments. Kogito provides REST APIs to fulfill all these requirements. Let’s split them in functional groups. 

Phase transitions

The REST template to transition from the current phase to another one is

POST http://<host:port>/<process id>/<process instance>/<task name>/<task instance id>/phase/<phase name>

As request body, you might optionally provide a JSON object whose key value pairs will be added to the task results. 

I guess there are too many template replacements to do, so let’s analyze them one by one, starting with <phase name>

Besides initial (Active) and final (Completed) states, Kogito provide these predefined phases

ClaimAllow the user to take ownership of the task
ReleaseAllow the owner to free ownership of the task
AbortThe task is aborted and process will finish with failure
SkipThe task is skipped and process will resume execution

In addition to them, Kogito allows users to define their custom phases, as described here. There are two pivotal methods to consider when adding a custom phase: mandatory public boolean canTransition(LifeCyclePhase phase), which determines if the transition is allowed from current to target phase and optional void apply(KogitoWorkItem workitem, Transition<?> transition), which gives the user freedom to modify the task information (workitem) using the information passed as body in the REST invocation (transition). You have a nice example of the powerful capabilities (including defining your own security policies) of apply method in Claim implementation. 

Approvals example

The rest of template substitutions depend on the process being used, hence I introduce you probably the simplest BPMN using human tasks in the world, the approval one. 

Using this process, the value for process id is approval and for task name is firstLineApproval or secondLineApproval.  process instance id should be obtained from the output of the call that starts the process (see here for more details on that). 

Retrieving list of tasks

Once the process is started, a task instance for firstLineApproval will be created and the process suspended. To obtain that task instance id, you need to retrieve the list of active tasks:

GET http://<host:port>/approvals/<process instance id>/tasks. 

This API will return a list of Task Model instances. Task Model is a POJO generated from process definition during its compilation. It contains information about the current task phase, tasks input parameters and task output results. Similar to the Task Model, input and output parameters are modeled as generated POJOs, each POJO containing a getter/setter pair per parameter. 

In approval process, as you can see in the companion diagrams, both firstLineApproval and secondLineApproval tasks share the same model.  Input data consists of a user defined POJO named traveller. Output is just  a boolean field called approved

Hence the generated input and output POJOS for firstLineApproval and secondLineApproval are:

public class Approvals_1_TaskInput {

   ....
    @UserTaskParam(value = ParamType.INPUT)
    private org.acme.travels.Traveller traveller;

    public org.acme.travels.Traveller getTraveller() {
        return traveller;
    }

    public void setTraveller(org.acme.travels.Traveller traveller) {
        this.traveller = traveller;
    }
}

public class Approvals_1_TaskOutput implements org.kie.kogito.MapOutput {

  .....

    @UserTaskParam(value = ParamType.OUTPUT)
    private java.lang.Boolean approved;

    public java.lang.Boolean getApproved() {
        return approved;
    }

    public void setApproved(java.lang.Boolean approved) {
        this.approved = approved;
    }
}

Therefore, the response of the call performed to retrieve the list of task instances will look this 

[
    {
        "id": "07f0f804-030b-4c50-8b61-684db9b748a4",
        "name": "firstLineApproval",
        "state": 0,
        "phase": "active",
        "phaseStatus": "Ready",
        "parameters": {
            "traveller": {
                "firstName": "John",
                "lastName": "Doe",
                "email": "jon.doe@example.com",
                "nationality": "American",
                "address": {
                    "street": "main street",
                    "city": "Boston",
                    "zipCode": "10005",
                    "country": "US"
                }
            }
        },
        "results": {
            "approved": null
        }
    }
]

Execute transition

As expected, the response contains only one active firstlineApproval (field name value). We are particularly interested in the id field, which value is the one to be used as task instance id. Since the task was just created (phaseStatus field is Ready),  there are not any results yet, hence the approved field has a value of null. Besides that, it is worth to mention that the parameters field contains a traveller instance, which was passed as part of the process starting request.

Now we have all the information we need to perform the phase transition REST invocation. Assuming you have deployed the process into your host at default port, the call to complete a task for this particular process instance will be (task instance id is highlighted in orange) :

URIhttp://localhost:8080/approvals/<process instance id>/firstLineApproval/07f0f804-030b-4c50-8b61-684db9b748a4/phase/complete
Body{“approved”:true}

Once this call is performed, the task will be completed (not longer being returned by tasks GET  APIs), its output will be set to {“approved”:true} and the process execution will be resumed.  

Saving results

A human task is a potentially long one, so, from time to time it might be wise to save the progress of it, or, as unfortunately happened to me with this post, you might be ending doing it twice. 

Saving a human task means adding results to it without performing a phase transition, operation that might be performed by passing as the whole output model as body of this call

PUT http://<host:port>/approvals/<process instance id>/<task name>/<task instance id>

Note that you need to pass the whole output model (in our approval example that’s not make any difference, since the output model consists of just one parameter) because by convention PUT, as an idempotent method, implies replacing the whole resource. 

You can check the model information about an active task at any moment by using

GET http://<host:port>/approvals/<process instance id>/<task name>/<task instance id>

Comments

In Kogito we consider that comments are entities in their own right, so they deserve a dedicated, although not independent, REST resource for them. That way all CRUD operations are supported over them, as illustrated below. 

MethodTemplate URIDescription
GET/<process_id>/<process_instance_id>/<task_name>/<task_instance id>/comments/<comment_id>Retrieve list of comments associated to the task
PUT/<process_id>/<process_instance_id>/<task_name>/<task_instance id>/comments/<comment_id>Updates a comment with the text passed in the body
POST/<process_id>/<process_instance_id>/<task_name>/<task_instance id>/commentsCreates a comment with the text passed in the body. Returns the comment id
DELETE/<process_id>/<process_instance_id>/<task_name>/<task_instance id>/comments/<comment_id>Deletes the comment

Attachments

Same rationale that was used for comments applies to attachments, the only differences being that the resource name is attachments rather than comments and that the body should be a valid URI, not any random string. 

MethodTemplate URIDescription
GET/<process_id>/<process_instance_id>/<task_name>/<task_instance id>/attachmentsRetrieve list of attachments associated to the task
PUT/<process_id>/<process_instance_id>/<task_name>/<task_instance id>/attachments/<attachment_id>Updates an attachment with the URI passed in the body
POST/<process_id>/<process_instance_id>/<task_name>/<task_instance id>/attachmentsCreates an attachment with the URI passed in the body. Returns the attachment id
DELETE/<process_id>/<process_instance_id>/<task_name>/<task_instance id>/attachments/<attachment_id>Deletes the attachment

Conclusion

In this post we have gone over the APIs provided by Kogito to operate with tasks from a process perspective. Next post will discuss the Task management API, which allows users with enough privileges to change task information not related with the process model. In other words, those task fields that are present for any task, regardless process definition.

4 1 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments