17.4. Remote Java API

The Remote Java API provides KieSession, TaskService and AuditService interfaces to the JMS and REST APIs.
The interface implementations provided by the Remote Java API take care of the underlying logic needed to communicate with the JMS or REST APIs. In other words, these implementations allow you to interact with Business Central through known interfaces such as the KieSession or TaskService interface, without having to deal with the underlying transport and serialization details.

Important

While the KieSession, TaskService and AuditService instances provided by the Remote Java API may "look" and "feel" like local instances of the same interfaces, make sure to remember that these instances are only wrappers around a REST or JMS client that interacts with a remote REST or JMS API.
This means that if a requested operation fails on the server, the Remote Java API client instance on the client side will throw a RuntimeException indicating that the REST call failed. This is different from the behavior of a "real" (or local) instance of a KieSession, TaskService and AuditService instance because the exception the local instances will throw will relate to how the operation failed. Also, while local instances require different handling (such as having to dispose of a KieSession), client instances provided by the Remote Java API hold no state and thus do not require any special handling.
Lastly, operations on a Remote Java API client instance that would normally throw other exceptions (such as the TaskService.claim(taskId, userId) operation when called by a user who is not a potential owner), will now throw a RuntimeException instead when the requested operation fails on the server.
The very first step in interacting with the remote runtime is to create the RemoteRuntimeEngine instance. The recommended way is to use RemoteRestRuntimeEngineBuilder or RemoteJmsRuntimeEngineBuilder. There are a number of different methods for both the JMS and REST client builders that allow the configuration of parameters such as the base URL of the REST API, JMS queue location or timeout while waiting for responses.

Procedure 17.1. Creating the RemoteRuntimeEngine Instance

  1. Instantiate the RemoteRestRuntimeEngineBuilder or RemoteJmsRuntimeEngineBuilder by calling either RemoteRuntimeEngineFactory.newRestBuilder() or RemoteRuntimeEngineFactory.newJmsBuilder().
  2. Set the required parameters.
  3. Finally, call the build() method.
Once the RemoteRuntimeEngine instance has been created, there are a couple of methods that can be used to instantiate the client classes you want to use:

Remote Java API Methods

KieSession RemoteRuntimeEngine.getKieSession()
This method instantiates a new (client) KieSession instance.
TaskService RemoteRuntimeEngine.getTaskService()
This method instantiates a new (client) TaskService instance.
AuditService RemoteRuntimeEngine.getAuditService()
This method instantiates a new (client) AuditService instance.
Starting the Project: Adding Dependencies

To start your own project, it is important to specify the BPM Suite BOM in the project's pom.xml file. Also, make sure you add the kie-remote-client dependency. See the following example:

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.jboss.bom.brms</groupId>
			<artifactId>jboss-brms-bpmsuite-bom</artifactId>
			<version>6.2.0.GA-redhat-1</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

<dependencies>
	<dependency>
		<groupId>org.kie.remote</groupId>
		<artifactId>kie-remote-client</artifactId>
	</dependency>
</dependencies>

17.4.1. The REST Remote Java RuntimeEngine Factory

The RemoteRuntimeEngineFactory class is the starting point for building and configuring a new RemoteRuntimeEngine instance that can interact with the remote API. This class creates an instance of a REST client builder using the newRestBuilder() method. This builder is then used to create a RemoteRuntimeEngine instance that acts as a client to the remote REST API. The RemoteRestRuntimeEngineBuilder exposes the following properties for configuration:

Table 17.12. RemoteRestRuntimeEngineBuilder Methods

Method Name Parameter Type Description
Url java.net.URL
URL of the deployed Business Central. For example: http://localhost:8080/business-central/.
UserName java.lang.String
The user name to access the REST API.
Password java.lang.String
The password to access the REST API.
DeploymentId java.lang.String
The name (id) of the deployment the RuntimeEngine must interact with. This can be an empty String in case you are only interested in task operations.
Timeout int
The maximum number of seconds the engine must wait for a response from the server.
ProcessInstanceId long
The method that adds the process instance id, which may be necessary when interacting with deployments that employ the per process instance runtime strategy.
ExtraJaxbClasses class
The method that adds extra classes to the classpath available to the serialization mechanisms. When passing instances of user-defined classes in a Remote Java API call, it is important to have added the classes using this method first so that the class instances can be serialized correctly.
Once you have configured all the necessary properties, call build() to get access to the RemoteRuntimeEngine.

Important

If the REST API access control is turned on, which is done by default, the given user who wants to use the RemoteRuntimeEngine calls has to have the rest-client and rest-all roles assigned.
Example usage

The following example illustrates how the Remote Java API can be used with the REST API.

import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.manager.RuntimeEngine;
import org.kie.api.runtime.process.ProcessInstance;
import org.kie.api.task.TaskService;
import org.kie.api.task.model.TaskSummary;
import org.kie.remote.client.api.RemoteRuntimeEngineFactory;

public void startProcessAndHandleTaskViaRestRemoteJavaAPI(
	URL instanceUrl, String deploymentId, String user, String password) {

	// The serverRestUrl should contain a URL similar to
	// "http://localhost:8080/business-central/".

	// Set up the factory class with the necessary information to communicate
	// with the REST services.

	RuntimeEngine engine = RemoteRuntimeEngineFactory
		.newRestBuilder()
		.addUrl(instanceUrl)
		.addUserName(user)
		.addPassword(password)
		.addDeploymentId(deploymentId)
		.build();
	KieSession ksession = engine
		.getKieSession();
	TaskService taskService = engine
		.getTaskService();

	// Each operation on a KieSession, TaskService or AuditService (client)
	// instance sends a request for the operation to the server side
	// and waits for the response. If something goes wrong on the server side,
	// the client will throw an exception.


	ProcessInstance processInstance = ksession
		.startProcess("project1.start_and_task_test");

	String taskUserId = user;
	long procId	= processInstance
		.getId();
	taskService	= engine
		.getTaskService();
	List<TaskSummary> tasks = taskService
		.getTasksAssignedAsPotentialOwner(user, "en-UK");
	long taskId = -1;

	for (TaskSummary task : tasks) {
		if (task.getProcessInstanceId() == procId) {
			taskId = task.getId();
		}
	}

	if (taskId == -1) {
		throw new IllegalStateException(
			"Unable to find task for "
			+ user
			+ " in process instance "
			+ procId);
	}

	taskService.start(taskId, taskUserId);
}

Note

To guarantee high performance, the getPotentialOwners() method of the TaskSummary class does not return the list of potential owners of a task.
Instead, you should retrieve information about owners on an individual task basis. In the following example, the mentioned Task is from the org.kie.api.task.model.Task package. Also notice that the method getTaskById() uses the task ID as a parameter.
import org.kie.api.task.model.OrganizationalEntity;
import org.kie.api.task.model.Task;

Task task = taskService.getTaskById(TASK_ID);
List<OrganizationalEntity> org = task.getPeopleAssignments().getPotentialOwners();

for (OrganizationalEntity ent : org) {
  System.out.println("org: " + ent.getId());
}
Further, actual owners and users created by them can be retrieved using the getActualOwnerId() and getCreatedById() methods.

17.4.2. Calling Tasks Without Deployment ID

The addDeploymentId() method called on the RemoteRestRuntimeEngineBuilder requires the calling application to pass the deploymentId parameter to connect to Business Central. The deploymentId is the ID of the deployment with which the RuntimeEngine interacts. However, there may be applications that require working with human tasks and dealing with processes across multiple deployments. In such cases, where providing deploymentId parameters for multiple deployments to connect to Business Central is not feasible, it is possible to skip the parameter when using the fluent API of the RemoteRestRuntimeEngineBuilder.
This API does not require the calling application to pass the deploymentId parameter. If a request requires the deploymentId parameter, but does not have it configured, an exception is thrown.
Here is an example to show this in action:
RuntimeEngine engine = RemoteRuntimeEngineFactory
	.newRestBuilder()
	.addUrl(instanceUrl)
	.addUserName(user)
	.addPassword(password)
	.build();

	// This call does not require the deployment ID and ends successfully:

	engine.getTaskService().claim(23l, "user");

	// This code throws a "MissingRequiredInfoException" because the
	// deployment ID is required:

	engine.getKieSession().startProcess("org.test.process");

17.4.3. Custom Model Objects and Remote API

Usage of custom model objects from a client application using the Remote API is supported in JBoss BPM Suite. Custom model objects are the model objects that you create using the Data Modeler within Business Central. Once built and deployed successfully into a project, these objects are part of the project in the local Maven repository.

Note

Reuse model objects instead of recreating them locally in the client application.
The process to access and manipulate these objects from the client application is detailed here:

Procedure 17.2. Accessing custom model objects using the Remote API

  1. Ensure that the custom model objects have been installed into the local Maven repository of the project that they are a part of. To achieve that, the project has to be built successfully.
  2. If your client application is a Maven based project include the custom model objects project as a Maven dependency in the pom.xml configuration file of the client application.
    <dependency>
    	<groupId>${groupid}</groupId>
    	<artifactId>${artifactid}</artifactId>
    	<version>${version}</version>
    </dependency>
    The value of these fields can be found in your Project Editor within Business Central: AuthoringProject Authoring in the main menu and then ToolsProject Editor from the perspective menu.
    • If the client application is not a Maven based project download the JBoss BPM Suite project, which includes the model classes, from Business Central by clicking on AuthoringArtifact Repository. Add this jar file of the project on the build path of your client application so that the model object classes can be found and used.
  3. You can now use the custom model objects within your client application and invoke methods on them using the Remote API. The following listing shows an example of this, where Person is a custom model object.
    RuntimeEngine engine = RemoteRuntimeEngineFactory
    	.newRestBuilder()
    	.addUrl(instanceUrl)
    	.addUserName(user)
    	.addPassword(password)
    	.addExtraJaxbClasses(Person.class)
    	.addDeploymentId(deploymentId)
    	.build();
    
    KieSession kSession = engine.getKieSession();
    
    Map<String, Object> params = new HashMap<>();
    Person person = new Person();
    person.setName("anton");
    params.put("pVar", person);
    ProcessInstance pi = kSession.startProcess(PROCESS2_ID, params);
    System.out.println("Process Started: " + pi.getId());
    
    Ensure that your client application has imported the correct JBoss BPM Suite libraries for the example to work.
If you are creating a data object, make sure that the class has the @org.kie.api.remote.Remotable annotation. The @org.kie.api.remote.Remotable annotation makes the entity available for use with JBoss BPM Suite remote services such as REST, JMS, and WS.
There are two ways to add the annotation:
  1. On the Drools & jBPM screen of the data object in Business Central, select the Remotable check box.
    Remotable check box on the Drools & jBPM screen in Business Central.

    Figure 17.1. Remotable check box on the Drools & jBPM screen in Business Central.

    You can also add the annotation manually. On the right side of the Data Object editor screen in Business Central, choose the Advanced tab and click add annotation. In the Add new annotation dialog window, define the annotatiton class name as org.kie.api.remote.Remotable and click the search button.
  2. It is also possible to edit the source of the class directly. See the following example:
    package org.bpms.helloworld;
    
    @org.kie.api.remote.Remotable
    
    public class Person implements java.io.Serializable {
    	...
    

17.4.4. The JMS Remote Java RuntimeEngine Factory

The RemoteRuntimeEngineFactory works similarly to the REST variation in that it is a starting point for building and configuring a new RemoteRuntimeEngine instance that can interact with the remote JMS API. The main use for this class is to create a builder instance of JMS using the newJmsBuilder() method. This builder is then used to create a RemoteRuntimeEngine instance that will act as a client to the remote JMS API. Illustrated in the table below are the various methods available for the RemoteJmsRuntimeEngineBuilder:

Table 17.13. RemoteJmsRuntimeEngineBuilder Methods

Method Name Parameter Type Description
addDeploymentId java.lang.String
Name (ID) of the deployment the RuntimeEngine should interact with.
addProcessInstanceId long
Name (ID) of the process the RuntimeEngine should interact with.
addUserName java.lang.String
User name needed to access the JMS queues (in your application server configuration).
addPassword java.lang.String
Password needed to access the JMS queues (in your application server configuration).
addTimeout int
Maximum number of seconds allowed when waiting for a response from the server.
addExtraJaxbClasses class
Adds extra classes to the classpath available to serialization mechanisms.
addRemoteInitialContext javax.jms.InitialContext
Remote InitialContext instance (created using JNDI) from the server.
addConnectionFactory javax.jms.ConnectionFactory
ConnectionFactory instance used to connect to the ksessionQueue or taskQueue.
addKieSessionQueue javax.jms.Queue
Instance of the Queue for requests related to a process instance.
addTaskServiceQueue javax.jms.Queue
Instance of the Queue for requests related to the task service usage.
addResponseQueue javax.jms.Queue
Instance of the Queue used for receiving responses.
addJbossServerUrl java.net.URL
URL for the JBoss Server and Websphere.
addJbossServerHostName java.lang.String
Host name for the JBoss Server.
addHostName java.lang.String
Host name of the JMS queues.
addJmsConnectorPort int
Port for the JMS Connector.
addKeystorePassword java.lang.String
JMS Keystore password.
addKeystoreLocation java.lang.String
JMS Keystore location.
addTruststorePassword java.lang.String
JMS Truststore password.
addTruststoreLocation java.lang.String
JMS Truststore location.
useKeystoreAsTruststore -
Should be used if the Keystore and Truststore are both located in the same file. Configures the client to use the file for both Keystore and Truststore.
useSsl boolean
Sets whether this client instance uses secured connection.
disableTaskSecurity -
Suitable only if you do not want to use SSL while communicating with Business Central.

Example Usage

The following example illustrates how the Remote Java API can be used with the JMS API.
import org.kie.api.runtime.KieSession;
import org.kie.api.task.TaskService;
import org.kie.api.runtime.process.ProcessInstance;
import org.kie.services.client.api.RemoteJmsRuntimeEngineFactory;
import org.kie.services.client.api.command.RemoteRuntimeEngine;

public void javaRemoteApiJmsExample
	(String deploymentId, Long processInstanceId, String user, String password) {

	// Create a factory class with all the values:
	RemoteJmsRuntimeEngineFactory jmsRuntimeFactory = RemoteRuntimeEngineFactory
		.newJmsBuilder()
		.addDeploymentId(deploymentId)
		.addProcessInstanceId(processInstanceId)
		.addUserName(user)
		.addPassword(password)
		.addRemoteInitialContext(remoteInitialContext)
		.addTimeout(3)
		.addExtraJaxbClasses(MyType.class)
		.useSsl(false)
		.build();

	RemoteRuntimeEngine engine = jmsRuntimeFactory.newRuntimeEngine();

	// Create KieSession and TaskService instances and use them:
	KieSession ksession = engine.getKieSession();
	TaskService taskService = engine.getTaskService();

	// Each operation on a KieSession, TaskService or AuditService (client) instance
	// sends a request for the operation to the server side and waits for the response.
	// If something goes wrong on the server side, the client will throw an exception.
	ProcessInstance processInstance
		= ksession.startProcess("com.burns.reactor.maintenance.cycle");
	long procId = processInstance.getId();

	String taskUserId = user;
	taskService = engine.getTaskService();
	List<TaskSummary> tasks = taskService
		.getTasksAssignedAsPotentialOwner(user, "en-UK");

	long taskId = -1;
	for (TaskSummary task : tasks) {
		if (task.getProcessInstanceId() == procId) {
			taskId = task.getId();
		}
	}

	if (taskId == -1) {
		throw new IllegalStateException
			("Unable to find task for "
			+ user 
			+ " in process instance " 
			+ procId);
	}

	taskService.start(taskId, taskUserId);
}

Configuration using an InitialContext instance

When configuring the RemoteJmsRuntimeEngineFactory with an InitialContext instance as a parameter for Red Hat JBoss EAP 6, it is necessary to retrieve the (remote) InitialContext instance first from the remote server. The following code illustrates how to do this.
private InitialContext getRemoteJbossInitialContext(URL url, String user, String password) {

	Properties initialProps = new Properties();
	initialProps.setProperty
		(InitialContext.INITIAL_CONTEXT_FACTORY,
		"org.jboss.naming.remote.client.InitialContextFactory");
	String jbossServerHostName = url.getHost();
	initialProps.setProperty
		(InitialContext.PROVIDER_URL, "remote://"+ jbossServerHostName + ":4447");
	initialProps.setProperty(InitialContext.SECURITY_PRINCIPAL, user);
	initialProps.setProperty(InitialContext.SECURITY_CREDENTIALS, password);

	for (Object keyObj : initialProps.keySet()) {
		String key = (String) keyObj;
		System.setProperty(key, (String) initialProps.get(key));
	}
	
	try {
		return new InitialContext(initialProps);
	} catch (NamingException e) {
		throw new RemoteCommunicationException
			("Unable to create " + InitialContext.class.getSimpleName(), e);
	}
}
You can work with JMS queues directly without using the RemoteRuntimeEngine. For more information, see the How to Use JMS Queues Without the RemoteRuntimeEngine in Red Hat JBoss BPMS article. However, this approach is not a recommended way to use the provided JMS interface.

17.4.5. Supported Methods

The Remote Java API provides client-like instances of the RuntimeEngine, KieSession, TaskService and AuditService interfaces. This means that while many of the methods in those interfaces are available, some are not. The following tables list the available methods. Methods not listed in the tables below throw an UnsupportedOperationException explaining that the called method is not available.

Table 17.14. Available process-related KieSession methods

Returns Method signature Description
void
abortProcessInstance(long processInstanceId)
Abort the process instance
ProcessInstance
getProcessInstance(long processInstanceId)
Return the process instance
ProcessInstance
getProcessInstance(long processInstanceId, boolean readonly)
Return the process instance
Collection<ProcessInstance>
getProcessInstances()
Return all (active) process instances
void
signalEvent(String type, Object event)
Signal all (active) process instances
void
signalEvent(String type, Object event, long processInstanceId)
Signal the process instance
ProcessInstance
startProcess(String processId)
Start a new process and return the process instance (if the process instance has not immediately completed)
ProcessInstance
startProcess(String processId, Map<String, Object> parameters);
Start a new process and return the process instance (if the process instance has not immediately completed)

Table 17.15. Available rules-related KieSession methods

Returns Method signature Description
Long
getFactCount()
Return the total fact count
Object
getGlobal(String identifier)
Return a global fact
void
setGlobal(String identifier, Object value)
Set a global fact

Table 17.16. Available WorkItemManager methods

Returns Method signature Description
void
abortWorkItem(long id)
Abort the work item
void
completeWorkItem(long id, Map<String, Object> results)
Complete the work item
void registerWorkItemHandler(String workItemName, WorkItemHandler handler)
Register the work items
WorkItem
getWorkItem(long workItemId)
Return the work item

Table 17.17. Available task operation TaskService methods

Returns Method signature Description
Long
addTask(Task task, Map<String, Object> params)
Add a new task
void
activate(long taskId, String userId)
Activate a task
void
claim(long taskId, String userId)
Claim a task
void
claimNextAvailable(String userId, String language)
Claim the next available task for a user
void
complete(long taskId, String userId, Map<String, Object> data)
Complete a task
void
delegate(long taskId, String userId, String targetUserId)
Delegate a task
void
exit(long taskId, String userId)
Exit a task
void
fail(long taskId, String userId, Map<String, Object> faultData)
Fail a task
void
forward(long taskId, String userId, String targetEntityId)
Forward a task
void
nominate(long taskId, String userId, List<OrganizationalEntity> potentialOwners)
Nominate a task
void
release(long taskId, String userId)
Release a task
void
resume(long taskId, String userId)
Resume a task
void
skip(long taskId, String userId)
Skip a task
void
start(long taskId, String userId)
Start a task
void
stop(long taskId, String userId)
Stop a task
void
suspend(long taskId, String userId)
Suspend a task

Table 17.18. Available task retrieval and query TaskService methods

Returns Method signature
Task
getTaskByWorkItemId(long workItemId)
Task
getTaskById(long taskId)
List<TaskSummary>
getTasksAssignedAsBusinessAdministrator(String userId, String language)
List<TaskSummary>
getTasksAssignedAsPotentialOwner(String userId, String language)
List<TaskSummary>
getTasksAssignedAsPotentialOwnerByStatus(String userId, List<Status>gt; status, String language)
List<TaskSummary>
getTasksOwned(String userId, String language)
List<TaskSummary>
getTasksOwnedByStatus(String userId, List<Status> status, String language)
List<TaskSummary>
getTasksByStatusByProcessInstanceId(long processInstanceId, List<Status> status, String language)
List<TaskSummary>
getTasksByProcessInstanceId(long processInstanceId)
Content
getContentById(long contentId)
Attachment
getAttachmentById(long attachId)

Note

The language parameter is not used for task retrieval and query TaskService methods anymore. However, the method signatures still contain it to support backward compatibility. This parameter will be removed in future releases.

Table 17.19. Available AuditService methods

Returns Method signature
List<ProcessInstanceLog>
findProcessInstances()
List<ProcessInstanceLog>
findProcessInstances(String processId)
List<ProcessInstanceLog>
findActiveProcessInstances(String processId)
ProcessInstanceLog
findProcessInstance(long processInstanceId)
List<ProcessInstanceLog>
findSubProcessInstances(long processInstanceId)
List<NodeInstanceLog>
findNodeInstances(long processInstanceId)
List<NodeInstanceLog>
findNodeInstances(long processInstanceId, String nodeId)
List<VariableInstanceLog>
findVariableInstances(long processInstanceId)
List<VariableInstanceLog>
findVariableInstances(long processInstanceId, String variableId)
List<VariableInstanceLog>
findVariableInstancesByName(String variableId, boolean onlyActiveProcesses)
List<VariableInstanceLog>
findVariableInstancesByNameAndValue(String variableId, String value, boolean onlyActiveProcesses)
void
clear()