| |
| = Kie Server Java Client API |
| |
| |
| The Kie Server has a great Java API to wrap REST or JMS requests to be sent to the server. |
| In this section we will explore some of the possibilities of this API. |
| |
| == Maven Configuration |
| |
| |
| if you are a Maven user, make sure you have at least the following dependencies in the project's _pom.xml_ |
| |
| .Maven Dependencies |
| [example] |
| |
| [source] |
| ---- |
| <dependency> |
| <groupId>org.kie.server</groupId> |
| <artifactId>kie-server-client</artifactId> |
| <version>${kie.api.version}</version> |
| </dependency> |
| <!-- Logging --> |
| <dependency> |
| <groupId>ch.qos.logback</groupId> |
| <artifactId>logback-classic</artifactId> |
| <version>1.1.2</version> |
| </dependency> |
| <!-- Drools Commands --> |
| <dependency> |
| <groupId>org.drools</groupId> |
| <artifactId>drools-compiler</artifactId> |
| <scope>runtime</scope> |
| <version>${kie.api.version}</version> |
| </dependency> |
| ---- |
| |
| |
| The version __kie.api.version __depends on the Kie Server version you are using. |
| For jBPM 6.3, for example, you can use 6.3.1-SNAPSHOT. |
| |
| == Client Configuration |
| |
| |
| The client requires a configuration object where you set most of the server communication aspects, such as the protocol (REST and JMS) credentials and the payload format (XStream, JAXB and JSON are the supported formats at the moment). The first thing to do is create your configuration then create the *``**KieServicesClient**``* object, the entry point for starting the server communication. |
| See the source below where we use a REST client configuration: |
| |
| |
| |
| .Client Configuration Example |
| [example] |
| |
| [source,java] |
| ---- |
| import org.kie.server.api.marshalling.MarshallingFormat; |
| import org.kie.server.client.KieServicesClient; |
| import org.kie.server.client.KieServicesConfiguration; |
| import org.kie.server.client.KieServicesFactory; |
| |
| public class DecisionServerTest { |
| |
| private static final String URL = "http://localhost:8080/kie-server/services/rest/server"; |
| private static final String USER = "kieserver"; |
| private static final String PASSWORD = "kieserver1!"; |
| |
| private static final MarshallingFormat FORMAT = MarshallingFormat.JSON; |
| |
| private KieServicesConfiguration conf; |
| private KieServicesClient kieServicesClient; |
| |
| public void initialize() { |
| conf = KieServicesFactory.newRestConfiguration(URL, USER, PASSWORD); |
| conf.setMarshallingFormat(FORMAT); |
| kieServicesClient = KieServicesFactory.newKieServicesClient(conf); |
| } |
| ---- |
| |
| === JMS interaction patterns |
| |
| In version 6.5 KIE Server Client JMS integration has been enhanced with possibility to use various interaction patterns. Currently available are: |
| |
| * request reply (which is the default) - that makes the JMS integration synchronous - it blocks client until it gets the response back - not suited for JMS transactional use case |
| * fire and forget - makes the integration one way only, suitable for notification like integration with kie server - makes perfect fit for transactional JMS delivery - deliver message to kie server only if transaction that ckie server client was invoked in was committed successfully |
| * async with callback - allows to not block a client after sending message to kie server and receive response asynchronously - can be integrated with transactional JMS delivery |
| |
| |
| Response handlers can be either set globally - when KieServicesConfiguration is created or it can be changed on runtime on individual client instances (like RuleServiceClient, ProcessServicesClient, etc) |
| |
| |
| While 'fire and forget' and 'request reply' patterns do not require any additional configuration 'async with callback' does. And the main thing is actually the callback. KIE Server CLient comes with one out of the box - `BlockingResponseCallback` that provides basic support backed by blocking queue internally. Size of the queue is confgurable and thus allow receiving multiple messages, though intention of this callback is that it will only receive one message at a time - so it's like one message (request) and then one response per client interaction. |
| |
| [NOTE] |
| |
| Kie Server Client when switching response handler is not thread safe, meaning change of the handler will affect all threads using same client instance. So in case of dynamic changes of the handler it's recommended to use separate client instances. A good approach is to maintain set of clients that use dedicated response handler and then use these clients dependeing on which handler is required. |
| |
| Example: |
| |
| client 1 will use fire and forget while client 2 will use request reply. So client 1 can be used to start processes and client 2 can be used to query for user tasks. |
| |
| Users can provide their own callbacks by implementing `org.kie.server.client.jms.ResponseCallback` interface. |
| |
| *Configuration* |
| |
| [example] |
| |
| [source,java] |
| |
| Global JMS configuration |
| ---- |
| InitialContext context = ...; |
| Queue requestQueue = (Queue) context.lookup("jms/queue/KIE.SERVER.REQUEST")); |
| Queue responseQueue = (Queue) context.lookup("jms/queue/KIE.SERVER.RESPONSE"); |
| ConnectionFactory connectionFactory = (ConnectionFactory) context.lookup("jms/RemoteConnectionFactory"); |
| KieServicesConfiguration jmsConfiguration = KieServicesFactory.newJMSConfiguration( connectionFactory, requestQueue, responseQueue, "user", "password"); |
| // here you set response handler globally |
| jmsConfiguration.setResponseHandler(new FireAndForgetResponseHandler()); |
| ---- |
| |
| Alternatively, might be actually more common, is to set the handler on individual clients before they are used |
| |
| [example] |
| |
| [source,java] |
| |
| Per client configuration |
| ---- |
| ProcessServiceClient processClient = client.getServicesClient(ProcessServicesClient.class); |
| // change response handler for processClient others are not affected |
| processClient.setResponseHandler(new FireAndForgetResponseHandler()); |
| --- |
| |
| == Server Response |
| |
| |
| All the service responses are represented by the object `org.kie.server.api.model.ServiceResponse<T>` where T is the type of the payload. |
| It has the following attributes: |
| |
| **String msg: **The response message; |
| |
| `org.kie.server.api.model.ServiceResponse.ResponseType`** type:** the response type enum, which can be SUCCESS or FAILURE; |
| |
| **T result: **The actual payload of the response, the requested object. |
| |
| Notice that this is the same object returned if you are using REST or JMS, in another words it is agnostic to protocol. |
| |
| == Server Capabilities |
| |
| |
| Decision Server initially only supported rules execution, starting in version 6.3 it started supporting business process execution. |
| To know what exactly your server support, you can list the server capabilities by accessing the object `org.kie.server.api.model.KieServerInfo`****using the client: |
| |
| |
| |
| .Listing Server capabilities |
| [example] |
| |
| [source,java] |
| ---- |
| public void listCapabilities() { |
| KieServerInfo serverInfo = kieServicesClient.getServerInfo().getResult(); |
| System.out.print("Server capabilities:"); |
| for(String capability: serverInfo.getCapabilities()) { |
| System.out.print(" " + capability); |
| } |
| System.out.println(); |
| } |
| ---- |
| If the server supports rules and process, the following should be printed when you run the code above: |
| |
| _Server capabilities: BRM KieServer BPM_ |
| |
| == Kie Containers |
| |
| |
| If you want to publish a kjar to receive requests, you must publish it in a container. |
| The container is represented in the client by the object ``org.kie.server.api.model.KieContainerResource``, and a list of resources is ``org.kie.server.api.model.KieContainerResourceList``. |
| Here's an example of how to print a list of containers: |
| |
| .Listing Kie Containers |
| [example] |
| |
| [source,java] |
| ---- |
| public void listContainers() { |
| KieContainerResourceList containersList = kieServicesClient.listContainers().getResult(); |
| List<KieContainerResource> kieContainers = containersList.getContainers(); |
| System.out.println("Available containers: "); |
| for (KieContainerResource container : kieContainers) { |
| System.out.println("\t" + container.getContainerId() + " (" + container.getReleaseId() + ")"); |
| } |
| } |
| ---- |
| |
| It is also possible to list the containers based on specific ReleaseId (and its individual parts) or status: |
| |
| .Listing Kie Containers with custom filter |
| [example] |
| |
| [source,java] |
| ---- |
| public void listContainersWithFilter() { |
| // the following filter will match only containers with ReleaseId "org.example:contatner:1.0.0.Final" and status FAILED |
| KieContainerResourceFilter filter = new KieContainerResourceFilter.Builder() |
| .releaseId("org.example", "container", "1.0.0.Final") |
| .status(KieContainerStatus.FAILED) |
| .build(); |
| KieContainerResourceList containersList = kieServicesClient.listContainers(filter).getResult(); |
| List<KieContainerResource> kieContainers = containersList.getContainers(); |
| System.out.println("Available containers: "); |
| for (KieContainerResource container : kieContainers) { |
| System.out.println("\t" + container.getContainerId() + " (" + container.getReleaseId() + ")"); |
| } |
| } |
| ---- |
| |
| == Managing Containers |
| |
| |
| You can use the client to dispose and create containers. |
| If you dispose a containers, a ServiceResponse will be returned with Void payload(no payload) and if you create it, the KieContainerResource object itself will be returned in the response. |
| Sample code: |
| |
| .Disposing and creating containers |
| [example] |
| |
| [source,java] |
| ---- |
| public void disposeAndCreateContainer() { |
| System.out.println("== Disposing and creating containers =="); |
| List<KieContainerResource> kieContainers = kieServicesClient.listContainers().getResult().getContainers(); |
| if (kieContainers.size() == 0) { |
| System.out.println("No containers available..."); |
| return; |
| } |
| KieContainerResource container = kieContainers.get(0); |
| String containerId = container.getContainerId(); |
| ServiceResponse<Void> responseDispose = kieServicesClient.disposeContainer(containerId); |
| if (responseDispose.getType() == ResponseType.FAILURE) { |
| System.out.println("Error disposing " + containerId + ". Message: "); |
| System.out.println(responseDispose.getMsg()); |
| return; |
| } |
| System.out.println("Success Disposing container " + containerId); |
| System.out.println("Trying to recreate the container..."); |
| ServiceResponse<KieContainerResource> createResponse = kieServicesClient.createContainer(containerId, container); |
| if(createResponse.getType() == ResponseType.FAILURE) { |
| System.out.println("Error creating " + containerId + ". Message: "); |
| System.out.println(responseDispose.getMsg()); |
| return; |
| } |
| System.out.println("Container recreated with success!"); |
| } |
| ---- |
| |
| == Available Clients for the Decision Server |
| |
| |
| The KieServicesClient is also the entry point for others clients to perform specific operations, such as send BRMS commands and manage processes. |
| Currently from the KieServicesClient you can have access to the following services available in `org.kie.server.client` package: |
| |
| * JobServicesClient: This client allows you to schedule, cancel, requeue and get job requests; |
| * ProcessServicesClient: Allows you to start, signal abort process; complete and abort work items among other capabilities; |
| * QueryServicesClient: The powerful query client allows you to query process, process nodes and process variables; |
| * RuleServicesClient: The simple, but powerful rules client can be used to send commands to the server to perform rules related operations(insert objects in the working memory, fire rules, get globals...); |
| * UserTaskServicesClient: Finally, the user tasks clients allows you to perform all operations with an user tasks(start, claim, cancel, etc) and query tasks by certain fields(process instances id, user, etc). |
| |
| |
| For further information about these interfaces check github: https://github.com/kiegroup/droolsjbpm-integration/tree/master/kie-server-parent/kie-server-remote/kie-server-client/src/main/java/org/kie/server/client |
| |
| You can have access to any of these clients using the method `getServicesClient` in the KieServicesClient class. |
| For example: `RuleServicesClient rulesClient = kieServicesClient.getServicesClient(RuleServicesClient.class);` |
| |
| == Sending commands to the server |
| |
| To build commands to the server you must use the class org.kie.api.command.KieCommands, that can be created using ``org.kie.api.KieServices.get().getCommands()``. |
| The command to be send must be a *BatchExecutionCommand* or a single command(if a single command is sent, the server wraps it into a BatchExecutionCommand): |
| |
| .Sending commands to a container |
| ==== |
| |
| [source,java] |
| ---- |
| public void executeCommands() { |
| System.out.println("== Sending commands to the server =="); |
| RuleServicesClient rulesClient = kieServicesClient.getServicesClient(RuleServicesClient.class); |
| KieCommands commandsFactory = KieServices.Factory.get().getCommands(); |
| Command<?> insert = commandsFactory.newInsert("Some String OBJ"); |
| Command<?> fireAllRules = commandsFactory.newFireAllRules(); |
| Command<?> batchCommand = commandsFactory.newBatchExecution(Arrays.asList(insert, fireAllRules)); |
| ServiceResponse<String> executeResponse = rulesClient.executeCommands("hello", batchCommand); |
| if(executeResponse.getType() == ResponseType.SUCCESS) { |
| System.out.println("Commands executed with success! Response: "); |
| System.out.println(executeResponse.getResult()); |
| } |
| else { |
| System.out.println("Error executing rules. Message: "); |
| System.out.println(executeResponse.getMsg()); |
| } |
| } |
| ---- |
| The result in this case is a String with the command execution result. |
| In our case it will print the following: |
| |
| |
| [source] |
| ---- |
| == Sending commands to the server == |
| Commands executed with success! Response: |
| { |
| "results" : [ ], |
| "facts" : [ ] |
| } |
| ---- |
| __\* You must add **org.drools:drools-compiler** dependency to have this part working__ |
| ==== |
| |
| During creation of BatchExecutionCommand, an optional *lookup* argument can be specified, that determines where the comand will run. |
| Lookup argument can be one of the following: |
| |
| * Kie Session Name defined in deployment descriptor |
| * Kie Container Id |
| * Kie Container Id followed by Process Instance Id (Process Instance runtime strategy have to be used on the container) |
| |
| The last two options need active jBPM extension on the Kie Container. |
| |
| In the third case, the usage of lookup argument looks like: |
| |
| [source,java] |
| ---- |
| Command<?> batchCommand = commandsFactory.newBatchExecution(Arrays.asList(insert, fireAllRules), "demo-container#1"); |
| ---- |
| |
| == Listing available business processes |
| |
| |
| To list process definitions we use the QueryClient. |
| The methods of the QueryClient usually uses pagination, which means that besides the query you are making, you must also provide the current page and the number of results per page. |
| In the code below the query for process definitions from the given container starts on page 0 and list 1000 results, in another words, the 1000 first results. |
| |
| |
| |
| .Listing Business Processes Definitions Example |
| [example] |
| |
| [source,java] |
| ---- |
| public void listProcesses() { |
| System.out.println("== Listing Business Processes =="); |
| QueryServicesClient queryClient = kieServicesClient.getServicesClient(QueryServicesClient.class); |
| List<ProcessDefinition> findProcessesByContainerId = queryClient.findProcessesByContainerId("rewards", 0, 1000); |
| for (ProcessDefinition def : findProcessesByContainerId) { |
| System.out.println(def.getName() + " - " + def.getId() + " v" + def.getVersion()); |
| } |
| } |
| ---- |