Custom functions for your Serverless Workflow service

The Cloud Native Computing Foundation (CNCF) specification supports the custom function type, which enables the implementations to extend the function definition capability.

Kogito supports the java and sysout custom types.

The CNCF specification does not support java and sysout functions. Therefore, these functions might not be portable across other implementations.

sysout custom function

You can use the sysout function for debugging or for quick demonstrations as shown in the following example:

Example of sysout function definition
{
  "functions": [
    {
      "name": "printMessage",
      "type": "custom",
      "operation": "sysout"
    }
  ]
}

In the state definition, you can call the same sysout function as shown in the following example:

Example of a sysout function reference within a state
{
  "states": [
    {
      "name": "myState",
      "type": "operation",
      "actions": [
        {
          "name": "printAction",
          "functionRef": {
            "refName": "printMessage",
            "arguments": {
              "message": "."
            }
          }
        }
      ]
    }
  ]
}

You must avoid using the sysout function in a production environment since it can spam the unnecessary data in the application log.

java custom function

Kogito supports the java functions within an Apache Maven project, in which you define your workflow service.

Function Definition

The following example shows the declaration of a java function:

Example of a java function declaration
{
  "functions": [
    {
      "name": "myFunction", (1)
      "type": "custom", (2)
      "operation": "service:java:com.acme.MyInterfaceOrClass::myMethod" (3)
    }
  ]
}
1 myFunction is the function name
2 custom is the function type
3 service:java:com.acme.MyInterfaceOrClass::myMethod is the custom operation definition. In the custom operation definition, service is the reserved operation keyword followed by the java keyword. com.acme.MyInterfaceOrClass is the FQCN (Fully Qualified Class Name) of the interface or implementation class followed by the method name (myMethod).

Function Arguments

Your method interface signature must copy the arguments passed by the workflow.

For example, if you invoke a function using one argument as follows, then your method signature assumes that the number model variable is an integer:

Example of a java function reference with one argument
{
 "functionRef": {
   "refName": "myFunction",
   "arguments": {
     "number": "${.number}"
   }
 }
Example of a java function implementation
public class MyInterfaceOrClass {

  public void myMethod(int number) {
        if (number % 2 != 0) {
            throw new IllegalArgumentException("Odd situation");
        }
    }
}

As a particular case, if you provide no argument in the workflow definition, the signature of the Java method might include a Jackson’s JsonNode parameter. This means that the Java method expects the entire workflow model as input.

When using the following example function reference with no arguments, and if the method signature contains a JsonNode parameter, the entire workflow model is passed when the method call is performed.

Example of a java function reference with no arguments
{
  "functionRef": {
    "refName": "myFunction"
   }
}
Example of a java function implementation
public class MyInterfaceOrClass {


    public JsonNode myMethod(JsonNode workflowData) {
        // do whatever I want with the Workflow model
        ......
        // return the modified content:
        return workflowData;
    }
}

Function return values

If your method returns a JsonNode, the content of that node is merged into the workflow model (you can use an action data filter to control what is merged).

The same occurs if your method returns any Java Object descendant that is not a primitive wrapper, the Java object is recursively converted to a JSON object and the result is merged into the workflow model (you can use an action data filter to control what is merged).

If your method returns a primitive type or their corresponding wrapper object (int, boolean, long, and so on), then the primitive value is added to the workflow model with the name response (you can change that name using an action data filter).

If your method returns Java collections, it is converted to a JSON array and added to the workflow model with the name response (you can change that name using an action data filter).

Function accessing Kogito context

If you need access to process contextual information (for example, Kogito process instance ID) inside your Java service, you can add a KogitoProcessContext parameter as the last one in the method signature.

Therefore, if you need to do so, you can update the signature of methods from previous sections.

Example of a function accessing Kogito context
public class MyInterfaceOrClass {


    public JsonNode myMethod(JsonNode workflowData, KogitoProcessContext context ) {
        // do whatever I want with the JsonNode and the Kogito process context
        ......
        // return the modified content:
        return workflowData;
    }
}
Example of a function accessing Kogito context
public class MyInterfaceOrClass {


    public void myMethod(int number, KogitoProcessContext context) {
        if (number % 2 != 0) {
            throw new IllegalArgumentException("Odd situation");
        }
    }
}

Avoid using java functions to call the external services, instead you can use the services orchestration features.

Found an issue?

If you find an issue or any misleading information, please feel free to report it here. We really appreciate it!