JBoss.orgCommunity Documentation

Chapter 17. Remote API

17.1. REST
17.1.1. Additional Information
17.1.2. Runtime calls
17.1.3. History calls
17.1.4. Task calls
17.1.5. Execute calls
17.2. JMS
17.2.1. JMS Queue setup
17.2.2. Example JMS usage
17.3. Remote Java API
17.3.1. Using the Remote Java RuntimeEngine API

REST API calls to the execution server allow you to manage processes and tasks and retrieve various dynamic information from the execution server. All calls are synchronous, that is, the call will only complete, including the possible return of a result, once the requested operation has succeeded.

When using Java code to interface with the REST API, the classes used in POST operations or otherwise returned by various operations can be found in the (org.kie.remote:)kie-services-client jar.

Serialization (json/jaxb)

Except for the Execute calls, all other REST calls described below can use either JAXB or JSON.

All REST calls, unless otherwise specified, will use JAXB serialization.

When using JSON, make sure to add the JSON media type ("application/json") to the ACCEPT header of your REST call.

Some of the REST calls below return lists of information. The results of these operations can be paginated, which means that the lists can be split up and returned according to the parameters sent by the user.

For example, if the REST call parameters indicate that page 2 with page size 10 should be returned for the results, then results 10 to (and including) 19 will be returned.

The first page is always page 1 (as opposed to page "0").


If both a "long" pagination parameter and its synonym are used, then only the value from the "long" variant is used. For example, if the page is given with a value of 11 and the p parameter is given with a value of 37, then the value of the page parameter, 11, will be used and the p parameter will be ignored.

For the following operations, pagination is always used. See above for the default values used.


This section lists REST calls that interface with

The deploymentId component of the REST calls below must conform to the following regex:

[POST] /runtime/{deploymentId}/process/{processDefId}/start
[GET] /runtime/{deploymentId}/process/instance/{procInstId}
[POST] /runtime/{deploymentId}/process/instance/{procInstId+}/abort
[POST] /runtime/{deploymentId}/process/instance/{procInstId}/signal
[GET] /runtime/{deploymentId}/process/instance/{procInstId}/variables
[POST] /runtime/{deploymentId}/signal
[GET] /runtime/{deploymentId}/workitem/{workItemId}
[POST] /runtime/{deploymentId}/workitem/{workItemId}/complete
[POST] /runtime/{deploymentId}/workitem/{workItemId: [0-9-]+}/abort
[POST] /runtime/{deploymentId}/history/clean
[GET] /runtime/{deploymentId}/history/instances
[GET] /runtime/{deploymentId}/history/instance/{procInstId}
[GET] /runtime/{deploymentId}/history/instance/{procInstId}/child
[GET] /runtime/{deploymentId}/history/instance/{procInstId}/node
[GET] /runtime/{deploymentId}/history/instance/{procInstId}/variable
[GET] /runtime/{deploymentId}/history/instance/{procInstId}/node/{nodeId}
[GET] /runtime/{deploymentId}/history/instance/{procInstId}/variable/{varId}
[GET] /runtime/{deploymentId}/history/process/{processDefId}
[GET] /runtime/{deploymentId}/history/variable/{varId}
[GET] /runtime/{deploymentId}/history/variable/{varId}/value/{value}
[GET] /runtime/{deploymentId}/history/variable/{varId}/instances
[GET] /runtime/{deploymentId}/history/variable/{varId}/value/{value}/instances

All of the task operation calls described in this section use the user (id) used in the REST basic authorization as input for the user parameter in the specific call.

Some of the operations take an optional lanaguage query parameter. If this parameter is not specified in the REST call, the default value of "en-UK" is used.

The taskId component of the REST calls below must conform to the following regex:

[POST] /task/{taskId}/activate
[POST] /task/{taskId}/claim
[POST] /task/{taskId}/claimnextavailable
[POST] /task/{taskId}/complete
[POST] /task/{taskId}/delegate
[POST] /task/{taskId}/exit
[POST] /task/{taskId}/fail
[POST] /task/{taskId}/forward
[POST] /task/{taskId}/nominate
[POST] /task/{taskId}/release
[POST] /task/{taskId}/resume
[POST] /task/{taskId}/skip
[POST] /task/{taskId}/start
[POST] /task/{taskId}/stop
[POST] /task/{taskId}/suspend
[GET] /task/query

The /task/query operation..

Except for the union parameter, if any of the other parameters are passed multiple times, this operation will query tasks based on the union of all values specific parameter. This is always true, regardless of the value of the union parameter.

For example, if multiple taskOwner parameters are passed, this operation will return all tasks that have a task owner matching at least one of the passed values.

However, behaviour with regards to multiple (types of) parameters is governed by the union parameter: if the unionparameter is passed as false, then the operation will query based on the intersection of the two sets of values.

For example, if both a taskOwner and taskId parameter are passed as well as a union parameter with a value of false, then the operation will query for tasks that have both the specified task owner and task id.

However, if the union parameter in the above example is true, then the operation will query for tasks that have either the specified task owner or the specified task id.

The following is a rather long example that shows how to use the JMS API. The numbers ("callouts") along the side of the example refer to notes below that explain particular parts of the example. It's supplied for those advanced users that do not wish to use the jBPM Remote Java API.

The jBPM Remote Java API, described here, will otherwise take care of all of the logic shown below.

import java.util.List;

import java.util.UUID;
import javax.jms.*;
import javax.naming.*;
import javax.xml.bind.JAXBException;
import org.drools.core.command.runtime.process.StartProcessCommand;
import org.jbpm.services.task.commands.GetTaskAssignedAsPotentialOwnerCommand;
import org.kie.api.command.Command;
import org.kie.api.runtime.process.ProcessInstance;
import org.kie.api.task.model.TaskSummary;
(1)import org.kie.services.client.serialization.jaxb.JaxbSerializationProvider;
import org.kie.services.client.serialization.jaxb.impl.JaxbCommandResponse;
import org.kie.services.client.serialization.jaxb.impl.JaxbCommandsRequest;
import org.kie.services.client.serialization.jaxb.impl.JaxbCommandsResponse;
import org.kie.services.client.serialization.jaxb.impl.JaxbExceptionResponse;
// ...
  String USER = "charlie";
  String PASSWORD = "ch0c0licious";
  String DEPLOYMENT_ID = "test-project";
  String PROCESS_ID_1 = "oompa-processing";
  
  // Create command
  Command<?> cmd = new StartProcessCommand(PROCESS_ID_1);
(5)  int oompaProcessingResultIndex = 0;
(2)  JaxbCommandsRequest req = new JaxbCommandsRequest(DEPLOYMENT_ID, cmd);
  req.getCommands().add(new GetTaskAssignedAsPotentialOwnerCommand(USER, "en-UK"));
(5)  int loompaMonitoringResultIndex = 1;
  // Setup queues
  
  InitialContext context;
  Queue sendQueue, responseQueue;
  try { 
      context = new InitialContext();
      sendQueue = (Queue) context.lookup("jms/queue/KIE.SESSION");
      responseQueue = (Queue) context.lookup("jms/queue/KIE.RESPONSE");
  } catch( NamingException ne ) { 
     throw new RuntimeException("Unable to lookup send or response queue", ne); 
  }
  Connection connection = null;
  Session session = null;
  JaxbCommandsResponse cmdResponse = null;
  String corrId = UUID.randomUUID().toString();
  String selector = "JMSCorrelationID = '" + corrId + "'";
  try {
      // Create JMS connection and session
      MessageProducer producer;
      MessageConsumer consumer;
      try {
          ConnectionFactory connectionFactory = (ConnectionFactory) context.lookup("jms/RemoteConnectionFactory");
          connection = connectionFactory.createConnection(USER, PASSWORD);
          session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
          producer = session.createProducer(sendQueue);
          consumer = session.createConsumer(responseQueue, selector);
          connection.start();
      } catch (JMSException jmse) {
          throw new RuntimeException("Unable to setup a JMS connection.", jmse);
      } catch (NamingException ne) {
          throw new RuntimeException("Unable to lookup JMS connection factory.", ne);
      }
      // Create msg
      BytesMessage msg;
      try {
(3)          msg = session.createBytesMessage();
(3)          msg.setJMSCorrelationID(corrId);
(3)          msg.setIntProperty("serialization", JaxbSerializationProvider.JMS_SERIALIZATION_TYPE);
(3)          String xmlStr = JaxbSerializationProvider.convertJaxbObjectToString(req);
          msg.writeUTF(xmlStr);
      } catch (JMSException jmse) {
          throw new RuntimeException("Unable to create and fill a JMS message.", jmse);
      } catch (JAXBException jaxbe) {
          throw new RuntimeException("Unable to deserialze JMS message.", jaxbe);
      }
      // Send msg
      try {
          producer.send(msg);
      } catch (JMSException jmse) {
          throw new RuntimeException("Unable to send a JMS message.", jmse);
      }
      // receive
      Message response;
      try {
          long qualityOfServiceThresholdMilliSeconds = 5 * 1000;
          response = consumer.receive(qualityOfServiceThresholdMilliSeconds);
      } catch (JMSException jmse) {
          throw new RuntimeException("Unable to receive or retrieve the JMS response.", jmse);
      }
      // extract response
      assert response != null : "Response is empty.";
      try {
          String xmlStr = ((BytesMessage) response).readUTF();
(4)          cmdResponse = (JaxbCommandsResponse) JaxbSerializationProvider.convertStringToJaxbObject(xmlStr);
      } catch (JMSException jmse) {
          throw new RuntimeException("Unable to extract " + JaxbCommandsResponse.class.getSimpleName()
                  + " instance from JMS response.", jmse);
      } catch (JAXBException jaxbe) {
          throw new RuntimeException("Unable to extract " + JaxbCommandsResponse.class.getSimpleName()
                  + " instance from JMS response.", jaxbe);
      }
      assert cmdResponse != null : "Jaxb Cmd Response was null!";
  } finally {
      if (connection != null) {
          try {
              connection.close();
              session.close();
          } catch (JMSException jmse) {
              System.out.println("Unable to close connection or session!");
              jmse.printStackTrace();
          }
      }
  }
  ProcessInstance oompaProcInst = null;
  List<TaskSummary> charliesTasks = null;
  for (JaxbCommandResponse<?> response : cmdResponse.getResponses()) {
(6)      if (response instanceof JaxbExceptionResponse) {
          JaxbExceptionResponse exceptionResponse = (JaxbExceptionResponse) response;
          throw new RuntimeException(exceptionResponse.getMessage());
      }
(5)      if (response.getIndex() == oompaProcessingResultIndex) {
(6)          oompaProcInst = (ProcessInstance) response.getResult();
(5)      } else if (response.getIndex() == loompaMonitoringResultIndex) {
(6)          charliesTasks = (List<TaskSummary>) response.getResult();
      }
  }

1

These classes can all be found in the (org.kie.remote:)kie-services-client jar.

2

The JaxbCommandsRequest instance is the "holder" object in which you can place all of the commands you want to execute in a particular request. By using the JaxbCommandsRequest.getCommands() method, you can retrieve the list of commands in order to add more commands to the request.

A deployment id is required for command request messages that deal with business processes. Command request messages that only contain human task-related commands do not require a deployment id.

3

Note that the JMS message sent to the remote JMS API must be constructed as follows:

  • It must be a JMS byte message.

  • It must have a filled JMS Correlation ID property.

  • It must have an int property with the name of "serialization" set to an acceptable value (only 0 at the moment).

  • It must contain a serialized instance of a JaxbCommandsRequest, added to the message as a UTF string

4

The same serialization mechanism used to serialize the request message will be used to serialize the response message.

5

In order to match the response to a command, to the initial command, use the index field of the returned JaxbCommandResponse instances. This index field will match the index of the initial command. Because not all commands will return a result, it's possible to send 3 commands with a command request message, and then receive a command response message that only includes one JaxbCommandResponse message with an index value of 1. That 1 then identifies it as the response to the second command.

6

Since many of the results returned by various commands are not serializable, the jBPM JMS Remote API converts these results into JAXB equivalents, all of which implement the JaxbCommandResponse interface. The JaxbCommandResponse.getResult() method then returns the JAXB equivalent to the actual result, which will conform to the interface of the result.

For example, in the code above, the StartProcessCommand returns a ProcessInstance. In order to return this object to the requester, the ProcessInstance is converted to a JaxbProcessInstanceResponse and then added as a JaxbCommandResponse to the command response message. The same applies to the List<TaskSummary> that's returned by the GetTaskAssignedAsPotentialOwnerCommand.

However, not all methods that can be called on a normal ProcessInstance can be called on the JaxbProcessInstanceResponse because the JaxbProcessInstanceResponse is simply a representation of a ProcessInstance object. This applies to various other command response as well. In particular, methods which require an active (backing) KieSession, such as ProcessInstance.getProess() or ProcessInstance.signalEvent(String type, Object event) will throw an UnsupportedOperationException.

By using the RemoteRestSessionFactory or RemoteJmsSessionFactory classes provided by the kie-services-client jar, you can create remote instances of the RuntimeEngine and thus also the KieSession and TaskService. These instances will allow you to interact with a remote workbench instance (i.e. KIE workbench or the jBPM Console) without having to deal with the underlying transport and serialization details.

In order to interact via REST with the remote runtime, the RemoteRestSessionFactory can be used. The following example illustrates how the remote session can be used.

  // Create REST session

  RemoteRestSessionFactory restSessionFactory 
    = new RemoteRestSessionFactory(deploymentId, deploymentUrl, user, password);
  RuntimeEngine engine = restSessionFactory.newRuntimeEngine();
  KieSession ksession = engine.getKieSession();
  ProcessInstance processInstance = ksession.startProcess("org.jbpm.humantask");
  
  TaskService taskService = engine.getTaskService();
  List<TaskSummary> tasks = taskService.getTasksAssignedAsPotentialOwner(taskUserId, "en-UK");
  long taskId = findTaskId(processInstance.getId(), tasks);
  
  Task task = taskService.getTaskById(taskId);
  
  taskService.start(taskId, taskUserId);
  taskService.complete(taskId, taskUserId, null);

In the above example, the following variables were used when initalizing the RemoteRestSessionFactory


See the various constructors of the RemoteRestSessionFactory class for more possibilities.