How to use the Bonita HTTP API

Looking for a quick way to learn how to use the Bonita HTTP API?

This blog post will guide you on how to configure your HTTP server using the BOS-Tomcat bundle (BOS-5.10.2-Tomcat-6.0.35) with different types of clients. This kind of installation is intended for deployments in which Bonita Open Solution will be deployed on a dedicated web application server, allowing different applications to reach BOS remotely via standard HTTP.

This blog post has two main parts: server side and client side. The server side configuration is common for everyone, while the client side is specific to each client type.

Server side

First get the bonita-server-rest.war from BOS-5.10.2-deploy ([deploy path]/bonita_execution_engine/interfaces/REST/without_engine) and copy it on your Tomcat bundle ([Tomcat path]/webapps). Start your server and your HTTP API is ready to use. It can be accessed via default user/password (restuser, restbpm). To change the username and/or password you need to go to your jaas configuration file (by default [Tomcat path]/external/security/jaas-standard.cfg) and modify the login context BonitaRESTServer:

BonitaRESTServer { org.ow2.bonita.identity.auth.BonitaRESTServerLoginModule required logins="restuser" passwords="restbpm" roles="restuser"; };

For example, if you want to use myuser/mypassword instead of restuser/restbpm, modify your login context as shown: BonitaRESTServer { org.ow2.bonita.identity.auth.BonitaRESTServerLoginModule required logins="myuser" passwords="mypassword" roles="restuser"; };

Note: The user defined here is a technical user, used only to give access to the HTTP API. This has nothing to do with the final user (actors in the processes). For this reason, it does not need to be included in the user database.
Attention: If you modify the “roles” option you also need to modify the web.xml.

Client side

There are three main types of clients for the Bonita HTTP API:

  • Bonita User Experience configured in HTTP mode
  • a Java Bonita client accessing the bonita API in the HTTP mode
  • an HTTP client

Each type of client requires different skill levels, so you can go directly to the one you are comfortable with.

Bonita User Experience in HTTP mode

If you want to configure Bonita User XP in to work in HTTP mode, configure the login context BonitaStore, in the JAAS configuration file, to use BonitaRESTLoginModule. In this login context you also need to configure access for the technical user that will be used by the application. The User XP will use this login and password to request authentication with the HTTP server, so this must match with the login/password defined in the login context BonitaRESTServer on the server side. For example:

BonitaStore { org.ow2.bonita.identity.auth.BonitaRESTLoginModule required restUser="restuser" restPassword="restbpm"; };

or if you have changed the login/password on the server side to myuser/mypassword:

BonitaStore { org.ow2.bonita.identity.auth.BonitaRESTLoginModule required restUser="myuser" restPassword="mypassword"; };

You also need to change the property org.ow2.bonita.api-type to REST and set your HTTP server address (org.ow2.bonita.rest-server-address). To do this, edit your <TOMCAT_HOME>/bin/setenv.bat if you are using Windows, or <TOMCAT_HOME>/bin/setenv.sh if you are using Linux or Mac OS.

setenv.bat

@echo on

rem Sets some variables
set BONITA_HOME=“-DBONITA_HOME=%CATALINA_HOME%\bonita”
set SECURITY_OPTS=“-Djava.security.auth.login.config=%CATALINA_HOME%\external\security\jaas-standard.cfg”
set APITYPE_OPTS=-Dorg.ow2.bonita.api-type=“REST”
set URL_OPTS=-Dorg.ow2.bonita.rest-server-address=“http://localhost:8080/bonita-server-rest/

set CATALINA_OPTS=%CATALINA_OPTS% %SECURITY_OPTS% %BONITA_HOME% %APITYPE_OPTS% %URL_OPTS% -Dfile.encoding=UTF-8 -Xshare:auto -Xms512m -Xmx1024m -XX:MaxPermSize=256m -XX:+HeapDumpOnOutOfMemoryError

setenv.sh

#!/bin/sh

Sets some variables

BONITA_HOME=“-DBONITA_HOME=$CATALINA_HOME/bonita”
SECURITY_OPTS=“-Djava.security.auth.login.config=$CATALINA_HOME/external/security/jaas-standard.cfg”
APITYPE_OPTS=“-Dorg.ow2.bonita.api-type=REST”
URL_OPTS=“-Dorg.ow2.bonita.rest-server-address=http://localhost:8080/bonita-server-rest/

CATALINA_OPTS=“$CATALINA_OPTS $BONITA_HOME $SECURITY_OPTS $APITYPE_OPTS $URL_OPTS -Dfile.encoding=UTF-8 -Xshare:auto -Xms512m -Xmx1024m -XX:MaxPermSize=256m -XX:+HeapDumpOnOutOfMemoryError”
export CATALINA_OPTS

You can now lunch the User XP and log in with admin/bpm.

Java client

If you are using a Java client you can use the classical Bonita API . In this way you don't need to worry about HTTP API details (URL, parameters and so on); the HTTP requests will be generated automatically. To get started with the Bonita API, take a look at the articles Building your BPM applications with Bonita Runtime, Part 1, Part 2 and Part 3. To use the Bonita API in HTTP mode, you need to:

  • Change your BonitaStore login context to use BonitaRESTLoginModule. In this login context you need to configure the technical user that will be used by the application. The client will use this login and password to request authentication with the server, so this must match with the login/password defined in the login context BonitaRESTServer on the server side.

For example:

BonitaStore { org.ow2.bonita.identity.auth.BonitaRESTLoginModule required restUser="restuser" restPassword="restbpm"; };

  • Go to your application code and set the system properties org.ow2.bonita.api-type to REST and org.ow2.bonita.rest-server-address to your HTTP server address.

The example below is a simple Maven project with dependency for bonita-client 5.10.2. In the Java code I deploy a very simple process, instantiate and execute it:

POM.xml

4.0.0 org.bonitasoft examples 1.0-SNAPSHOT org.ow2.bonita bonita-client 5.10.2

Client.java

/** * Copyright (C) 2011 BonitaSoft S.A. * BonitaSoft, 31 rue Gustave Eiffel - 38000 Grenoble * This library is free software; you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Foundation * version 2.1 of the License. * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301, USA. **/ package org.bonitasoft.examples;

import java.util.Collection;

import javax.security.auth.login.LoginContext;

import org.ow2.bonita.facade.ManagementAPI;
import org.ow2.bonita.facade.QueryRuntimeAPI;
import org.ow2.bonita.facade.RuntimeAPI;
import org.ow2.bonita.facade.def.majorElement.ProcessDefinition;
import org.ow2.bonita.facade.runtime.ActivityState;
import org.ow2.bonita.facade.runtime.InstanceState;
import org.ow2.bonita.facade.uuid.ProcessDefinitionUUID;
import org.ow2.bonita.facade.uuid.ProcessInstanceUUID;
import org.ow2.bonita.light.LightTaskInstance;
import org.ow2.bonita.util.AccessorUtil;
import org.ow2.bonita.util.BonitaConstants;
import org.ow2.bonita.util.BusinessArchiveFactory;
import org.ow2.bonita.util.ProcessBuilder;
import org.ow2.bonita.util.SimpleCallbackHandler;

/**

  • @author Elias Ricken de Medeiros

*/
public class Client {

private static final String LOGIN = “john”;
private static final String PSSWD = “bpm”;
private static final String jaasFile = “src/main/resources/jaas-standard.cfg”;

public static void main(String args) throws Exception {

//set system properties
System.setProperty(BonitaConstants.API_TYPE_PROPERTY, "REST");
System.setProperty(BonitaConstants.REST_SERVER_ADDRESS_PROPERTY, "http://localhost:8080/bonita-server-rest/");
System.setProperty(BonitaConstants.JAAS_PROPERTY, jaasFile);

//login
//verify the user exists
LoginContext loginContext = new LoginContext("BonitaAuth",
    new SimpleCallbackHandler(LOGIN, PSSWD));
loginContext.login();
loginContext.logout();

//propagate the user credentials
loginContext = new LoginContext("BonitaStore",
    new SimpleCallbackHandler(LOGIN, PSSWD));
loginContext.login();

//get he APIs
final ManagementAPI managementAPI = AccessorUtil.getManagementAPI();
final RuntimeAPI runtimeAPI = AccessorUtil.getRuntimeAPI();
final QueryRuntimeAPI queryRuntimeAPI = AccessorUtil.getQueryRuntimeAPI();

try {
  
  //create a simple process with process builder: 
  // - one step with LOGIN as actor
  // - a Global data of String Type
  ProcessDefinition process = ProcessBuilder.createProcess("myProcess", "1.0")
    .addStringData("globalVar", "defaultValue")
    .addHuman(LOGIN)
    .addHumanTask("step1", LOGIN)
    .done();
  
  //deploy process
  process = managementAPI.deploy(BusinessArchiveFactory.getBusinessArchive(process));
  
  System.out.println("----------------\nProcess deployed\n----------------");
  
  final ProcessDefinitionUUID processUUID = process.getUUID();
  //instantiate process
  ProcessInstanceUUID instanceUUID = runtimeAPI.instantiateProcess(processUUID);
  System.out.println("----------------\nNew process instance Created\n----------------");
  
  final Collection<LightTaskInstance> taskList = queryRuntimeAPI.getLightTaskList(instanceUUID, ActivityState.READY);
  if (taskList.size() != 1) {
    throw new Exception("Incorrect list size. Actual size: " + taskList.size());
  }
  
  //execute task
  final LightTaskInstance taskInstance = taskList.iterator().next();
  runtimeAPI.executeTask(taskInstance.getUUID(), true);
  System.out.println("----------------\nTask executed\n----------------");
  
  final InstanceState state = queryRuntimeAPI.getProcessInstance(instanceUUID).getInstanceState();
  if(!state.equals(InstanceState.FINISHED)){
    throw new Exception("Incorrect state. Actual state: " + state);
  }
  
  System.out.println("----------------\nApplication executed sucessfully\n----------------");

} finally {
  //delete all deployed processes
  managementAPI.deleteAllProcesses();
  loginContext.logout();
}

}

}

Output

Infos: API-Type: REST has been specified through property: org.ow2.bonita.api-type ---------------- Process deployed ---------------- ---------------- New process instance Created ---------------- ---------------- Task executed ---------------- ---------------- Application executed sucessfully ----------------

HTTP Client

If you need to use an HTTP client, you must have acknowledgement of the Bonita HTTP API. All HTTP requests will be done using the POST method. All requests, except checkUserCredentials, checkUserCredentialsWithPasswordHash, and getIdentityKeyFromTemporaryToken, will require authentication using HTTP Basic. For authentication purposes you must use one of the technical users (login and password) defined on the server side (BonitaRESTServer login context). In addition, you must indicate the logged in final user. This information will be used in the process execution. For instance, if you use the HTTP API to execute a task, it is this final user who will be recorded as the Actor who executed the Task. This is equivalent to the username used to do login in Bonita User XP or the username used to do login in the Java client. The final User is defined using the form parameter named “options”. Use the syntax "user:username". For instance, if john is the final user, set the "options" parameter with the content "user:john". The options parameter also can be used to set domain and queryList.

Attention: No verification is done on the server side to check the final user credentials, so you need to manage this.

How to use the parameters

The Bonita HTTP API uses three types of parameters:

  • Path parameter: this kind of parameter is identified by the symbols “{“ and “}” in the URL path. To use them, replace “{parameter name}” by its value. For instance, for the method getProcessesByState:

/API/queryDefinitionAPI/getProcessesByState/{processState}

becomes

/API/queryDefinitionAPI/getProcessesByState/READY

  • Query parameter: this kind of parameter is placed after the symbol “?” in the URL. They are listed in the method detail. To define a value for a query parameter, put its value after the symbol “=”. For instance, for the method getLightProcessesByIndexAndPageSize

/API/queryDefinitionAPI/getLightProcessesByIndexAndPageSize?fromIndex=&pageSize=

becomes

/API/queryDefinitionAPI/getLightProcessesByIndexAndPageSize?fromIndex=0&pageSize=20

  • Form parameter: Unlike the query and path parameters, a form parameter is not passed in the URL, but in the body of the HTTP request. All form parameters are listed in the method detail. To use them, add the parameter to the HTTP request content and use the header “Content-Type” with the value “application/x-www-form-urlencoded”. For instance, to set john as final user using the “options” parameter (available in all methods), add the header “Content-Type:application/x-www-form-urlencoded” to the HTTP request and add the value “options=user:john” to its content.

About the String representation

Each HTTP API item is associated to one method of the classical Bonita API. This is listed on the right side, on the "API Example." To see the parameter string representation, verify in the classical API the parameter Java type and then see how this Java type is mapped into a String in the section Examples of Java Object String Representation. Below you will find an example of how to use the methods instantiateProcess (instantiate a process), instantiateProcessWithVariables (instantiate a process and initialise variables) and getLightProcessInstances (get the set of all processes instances). First I'll show HTTP requests via Java and then I'll do the same request using a REST Client. HTTP via Java :

/** * Copyright (C) 2011 BonitaSoft S.A. * BonitaSoft, 31 rue Gustave Eiffel - 38000 Grenoble * This library is free software; you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Foundation * version 2.1 of the License. * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301, USA. **/ package org.bonitasoft.examples;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLEncoder;

import org.ow2.bonita.util.Base64;

/**

  • @author Elias Ricken de Medeiros

*/
public class HTTPURLConnectionClient {
public static void main(String args) throws Exception {
//instantiateProcess method
//the given process must be deployed before
System.out.println(“--------------\nCreating a new process instance (variables with default values)\n--------------\n”);
String url = “http://localhost:8080/bonita-server-rest/API/runtimeAPI/instantiateProcess/myProcess--1.0”;
String parameters = “options=user:john”;
HttpURLConnection connection = getConnection(url, parameters);
processResponse(connection);

//instantiateProcessWithVariables
System.out.println("\n--------------\nCreating a new process instance (variables with initialized values)\n--------------\n");
url = "http://localhost:8080/bonita-server-rest/API/runtimeAPI/instantiateProcessWithVariables/myProcess--1.0";
String xmlVariables="<map><entry><string>globalVar</string><string>new value</string></entry></map>";
xmlVariables = URLEncoder.encode(xmlVariables, "UTF-8");
parameters = "options=user:john&variables="+xmlVariables;
connection = getConnection(url, parameters);
processResponse(connection);

System.out.println("\n--------------\nRetriving all process instances ...\n--------------\n");
//get light process instances
url = "http://localhost:8080/bonita-server-rest/API/queryRuntimeAPI/getProcessInstances";
parameters = "options=user:john";
connection = getConnection(url, parameters);
processResponse(connection);

}

private static HttpURLConnection getConnection(final String url, final String parameters) throws IOException,
MalformedURLException, ProtocolException {
final HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setUseCaches (false);
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod(“POST”);
connection.setRequestProperty(“Content-Type”, “application/x-www-form-urlencoded”);
connection.setRequestProperty(“Authorization”, "Basic " + Base64.encodeBytes(“restuser:restbpm”.getBytes()));

final DataOutputStream output = new DataOutputStream(connection.getOutputStream());
output.writeBytes(parameters);
output.flush();
output.close();
connection.disconnect();

return connection;

}

/**

  • @param connection
  • @throws IOException
    */
    private static void processResponse(HttpURLConnection connection)
    throws IOException {
    int responseCode = connection.getResponseCode();
    if(responseCode != HttpURLConnection.HTTP_OK){
    System.out.println(“----------\nRequest failled: " + responseCode+ “\n----------”);
    } else {
    System.out.println(”----------\nResponse content: \n----------");
    final InputStream is = connection.getInputStream();
    final BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    String line;
    StringBuffer response = new StringBuffer();
    try {
    while((line = reader.readLine()) != null) {
    response.append(line);
    response.append(‘\n’);
    }
    } finally {
    reader.close();
    is.close();
    }
    System.out.println(response.toString().trim());
    }
    }

}

Java output

-------------- Creating a new process instance (variables with default values) --------------


Response content:

myProcess--1.0--1

Creating a new process instance (variables with initialized values)


Response content:

myProcess--1.0--2

Retriving all process instances …


Response content:

myProcess--1.0 myProcess--1.0--1 myProcess--1.0--1 1 1399906081104 STARTED 0 john 1399906081080 false globalVar defaultValue 0 1399906081080 john STARTED STARTED myProcess--1.0 myProcess--1.0--1 myProcess--1.0--1 myProcess--1.0--1--step1--it1--mainActivityInstance--noLoop it1 mainActivityInstance noLoop READY 1399906081102 step1 0 0 1399906081088 myProcess--1.0--step1 0 0 Human true 0 1399906081088 READY SYSTEM READY 0 1399906081104 READY SYSTEM john john john john myProcess--1.0 myProcess--1.0--2 myProcess--1.0--2 2 1399906081260 STARTED 0 john 1399906081239 false globalVar new value 0 1399906081239 john STARTED STARTED myProcess--1.0 myProcess--1.0--2 myProcess--1.0--2 myProcess--1.0--2--step1--it1--mainActivityInstance--noLoop it1 mainActivityInstance noLoop READY 1399906081259 step1 0 0 1399906081247 myProcess--1.0--step1 0 0 Human true 0 1399906081247 READY SYSTEM READY 0 1399906081260 READY SYSTEM john john john john

REST client

Follow the steps below to do the same operations using a REST client.

  • Enter the URL(http://localhost:8080/bonita-server-rest/API/runtimeAPI/instantiateProcess/myProcess--1.0) and choose POST as HTTP method

  • Go to the headers tab and add the key/value: Content-Type:application/x-www-form-urlencoded:

  • Go to the Body tab and add your request's form parameters. For example:

options=user:john

  • Go to the Auth tab, choose Basic as Auth type and enter the technical username and password for authentication.

  • Execute the request.

Note: This assumes you've deployed a process having the UUID "myProcess--1.0". In the response you can see the UUID of the created instance.

  • Now change the URL to http://localhost:8080/bonita-server-rest/API/runtimeAPI/instantiateProcessWithVariables/myProcess--1.0 and add the following keys/values in your HTTP body:

options=user:john variables=globalVarnew value This assumes you have a global variable of type Text with the name "globalVar" in your process. It will be initialiazed with the value "new value".

  • Execute the new request and verify the returned instance UUID.

  • Finally, for my last example, change your URL to http://localhost:8080/bonita-server-rest/API/queryRuntimeAPI/getLightProcessInstances and add the paramater options=user:john to your request.

  • Execute the request and verify the list of all process instances.

Now you have an idea of how to configure Bonita Open Solution on your dedicated web application (HTTP) server to use a Java client and an HTTP client. Your feedback is welcome!