Create your first application with Bonita Java APIs

Learn how to set up a Maven client application that uses Bonita Java APIs to communicate with Bonita Engine and run a process.

It assumes that you are a Java programmer familiar with Maven.

Bonita Client APIs

In this example, we use the following APIs:

  • LoginAPI: Manages the login on tenants. Using this API you can obtain an APISession, which is required for access to the tenant APIs, such as the IdentityAPI and the ProcessAPI.

  • ProcessAPI: Manages processes. Using this API you can handle process execution (for example, start a process, retrieve a task, execute a task, or retrieve data) and process management (for example, deploy, undeploy, enable or disable a process).

Maven dependencies

In order to use the client APIs, you need to add a dependency to the bonita-client artifact in your Maven pom.xml file:

<properties>
   <bonita.bpm.version>8.0.0</bonita.bpm.version>
   ...
</properties>

<!-- Bonita Engine -->
<dependency>
    <groupId>org.bonitasoft.engine</groupId>
    <artifactId>bonita-client</artifactId>
    <version>${bonita.bpm.version}</version>
</dependency>
<!-- If you use Subscription edition, use this dependency instead: -->
<!--dependency>
    <groupId>com.bonitasoft.engine</groupId>
    <artifactId>bonita-client-sp</artifactId>
    <version>${bonita.bpm.version}</version>
</dependency-->

Configure the connection to the Bonita Platform

You must configure the connection to the Engine (i.e. Bonita Platform) for your project. To do so you can use System properties or programmatic configuration.

Take a look at how to configure a client

Log in

The first action of the client must be to log in. This example shows how to log in when accessing the server over HTTP:

// Let's set the connection settings to use HTTP on the already running Bonita runtime:
Map<String, String> settings = new HashMap<String, String>();
settings.put("server.url", "http://localhost:8080");
settings.put("application.name", "bonita");
// HTTP Basic Auth is active by default on server-side:
settings.put("basicAuthentication.active", "true");
settings.put("basicAuthentication.username", "http-api");  // default value, can be changed server-side in file <BONITA>/server/conf/tomcat-users.xml
settings.put("basicAuthentication.password", "h11p-@p1");  // default value, can be changed server-side in file <BONITA>/server/conf/tomcat-users.xml
APITypeManager.setAPITypeAndParams(ApiAccessType.HTTP, settings);

// First of all, let's log in on the engine:
org.bonitasoft.engine.api.APIClient apiClient = new APIClient();
apiClient.login(username, password); // use "install" / "install" if you don't have any other user created

Example of a client program

In this example, a user interacts with a Bonita process by choosing actions from a command-line client program written in Java.

The user can choose one of the following actions:

  • start a process

  • list open process instances: process instances that have not yet completed

  • list archived process instances: process instances that have completed

  • list pending tasks

  • execute a task

The program displays a menu presented by the getMenutTextContent method:

private static String getMenutTextContent() {
   StringBuilder stb = new StringBuilder("\nChoose the action to be executed:\n");
   stb.append("0 - exit\n");
   stb.append("1 - start a process\n");
   stb.append("2 - list open process instances\n");
   stb.append("3 - list archived process instances\n");
   stb.append("4 - list pending tasks \n");
   stb.append("5 - execute a task\n");
   stb.append("Choice:");
   return stb.toString();
   }

These choices are interpreted by the following code:

private static void executeActions(ProcessDefinition processDefinition)
    throws IOException, BonitaException {
    String message = getMenutTextContent();
    String choice = null;
    do {
        // show the menu and read the action chosen by the user
        choice = readLine(message);
        if ("1".equals(choice)) {
            // if user chooses 1, start a new process instance
            startProcess(processDefinition);
        } else if ("2".equals(choice)) {
            // if user chooses 2, list open process instances
            listOpenedProcessInstances();
        } else if ("3".equals(choice)) {
            // if user chooses 3, list archived process instances
            listArchivedProcessInstances();
        } else if ("4".equals(choice)) {
            // if user chooses 4, list pending tasks
            listPendingTasks();
        } else if ("5".equals(choice)) {
            // if user chooses 5, execute the task chosen by the user
            executeATask();
        } else if (!"0".equals(choice)) {
            System.out.println("Invalid choice!");
        }
    } while (!"0".equals(choice));
}

Start a process

private static void startProcess(ProcessDefinition processDefinition) {
    ProcessAPI processAPI = apiClient.getProcessAPI();
    ProcessInstance processInstance = processAPI.startProcess(processDefinition.getId());
}

List open process instances

All Bonita Java API methods that deal with collections are paged to avoid having too many entries in memory. For these methods, if you want to retrieve all results you need to handle this page by page. This the case with the searchProcessInstances method used here to retrieve open process instances. In the example, each page will contain up to 5 (PAGE_SIZE) elements:

private static void listOpenedProcessInstances() {
    // the result will be retrieved by pages of PAGE_SIZE size
    int startIndex = 0;
    int page = 1;
    SearchResult<ProcessInstance> result = null;
    do {
        // get the current page of open process instances
        result = getOpenProcessInstancePage(apiClient, startIndex);
        // print the current page
        printOpenedProcessIntancesPage(page, result);

        // go to next page
        startIndex += PAGE_SIZE;
        page++;
    } while (result.getResult().size() == PAGE_SIZE);
}
private static SearchResult<ProcessInstance> getOpenProcessInstancePage(APIClient apiClient, int startIndex) throws BonitaException {
    // create a new SeachOptions with given start index and PAGE_SIZE as max number of elements
    SearchOptionsBuilder optionsBuilder = new SearchOptionsBuilder(startIndex, PAGE_SIZE);
    // sort the result by the process instance id in ascending order
    optionsBuilder.sort(ProcessInstanceSearchDescriptor.ID, Order.ASC);
    // perform the request and return the result
    ProcessAPI processAPI = apiClient.getProcessAPI();
    return processAPI.searchProcessInstances(optionsBuilder.done());
}

List archived process instances

In order to retrieve all archived process instances you also need to iterate page by page:

private static void listArchivedProcessInstances() {
    // the result will be retrieved by pages of PAGE_SIZE size
    int startIndex = 0;
    int page = 1;
    SearchResult<ArchivedProcessInstance> result = null;
    do {
        // get the current page of opened process instances
        result = getArchivedProcessInstancePage(apiClient, startIndex);
        // print the current page
        printArchivedProcessInstancePage(page, result);

        // go to the next page
        startIndex += PAGE_SIZE;
        page++;
    } while (result.getResult().size() == PAGE_SIZE);
}
private static SearchResult<ArchivedProcessInstance> getArchivedProcessInstancePage(APIClient apiClient, int startIndex) throws BonitaException {
    // create a new SeachOptions with given start index and PAGE_SIZE as max number of elements
    SearchOptionsBuilder optionsBuilder = new SearchOptionsBuilder(startIndex, PAGE_SIZE);
    // when process instances are archived the original process instance id is supplied by SOURCE_OBJECT_ID,
    // so the result will be sort by the SOURCE_OBJECT_ID
    optionsBuilder.sort(ArchivedProcessInstancesSearchDescriptor.SOURCE_OBJECT_ID, Order.ASC);
    // perform the request and return the result;
    ProcessAPI processAPI = apiClient.getProcessAPI();
    return processAPI.searchArchivedProcessInstances(optionsBuilder.done());
}

List pending tasks

To get the pending tasks for the logged user, you use the method getPendingHumanTaskInstances.

private static void listPendingTasks() {
    ProcessAPI processAPI = apiClient.getProcessAPI();
    // the result will be retrieved by pages of PAGE_SIZE size
    int startIndex = 0;
    int page = 1;
    List<HumanTaskInstance> pendingTasks = null;
    do {
        // get the current page
        pendingTasks = processAPI.getPendingHumanTaskInstances(session.getUserId(), startIndex, PAGE_SIZE, ActivityInstanceCriterion.LAST_UPDATE_ASC);
        // print the current page
        printTasksPage(page, pendingTasks);

        // got to next page
        startIndex += PAGE_SIZE;
        page++;
    } while (pendingTasks.size() == PAGE_SIZE);
}

Execute a task

Before a user can execute a task, the task needs to be assigned to the user. The assignUserTask method assigns the task to the user. The executeFlowNode method executes the task.

private static void executeATask() {
    processAPI.assignUserTask(taskToExecute.getId(), session.getUserId());

    processAPI.executeFlowNode(taskToExecute.getId());
}