In this article we will cover the basics of KJAR deployments units, discussing what is a KJar archive and how to build run and deploy a KJAR file in standalone mode or on a Container. (Updated to 29/11/2021)
Pre-requisites:
- Read an introduction about Drools Rule system: Drools tutorial – The Rule Engine made simple
What is a KJar archive?
Firstly, a KJAR archive is pretty much like a JAR file, but with some key differences:
- A KJAR includes resources such as Rules and Process you can run a Container like jBPM
- A KJAR also includes a descriptor named META-INF/kmodule.xml which describes the structure and artifacts includes
- Optionally, a KJAR can include a file named META-INF/kie-deployment-descriptor.xml which can set properties as process runtime strategy, event listeners, work item handlers, and more.
- You need to use the following packaging for a KJAR:
<packaging>kjar</packaging>
- A KJAR uses the KIE Maven plugin to pre-compile some rule and process assets which otherwise will be built at runtime.
<plugin> <groupId>org.kie</groupId> <artifactId>kie-maven-plugin</artifactId> <version>${drools.version}</version> <extensions>true</extensions> </plugin>
Creating a KJAR from the Command Line
Creating a KJAR from the Command Line is pretty simple as you can rely on the available Maven archetypes. For example, to create a KJAR which uses Drools Rules:
mvn archetype:generate -B -DarchetypeGroupId=org.kie -DarchetypeArtifactId=kie-drools-archetype -DarchetypeVersion=7.61.0.Final -DgroupId=com.sample -DartifactId=basicKjar -Dversion=1.0-SNAPSHOT -Dpackage=com.sample
Let’s see the basic structure of an application created with the above archetype:
src ├── main │ ├── java │ │ └── com │ │ └── sample │ │ └── Measurement.java │ └── resources │ ├── META-INF │ │ └── kmodule.xml │ └── org │ └── example │ └── rules.drl └── test ├── java │ └── com │ └── sample │ └── RuleTest.java └── resources └── log4j.properties
As you can see, a simple Rule is available in the resources/org/example/rules.drl :
package com.sample; global java.util.Set controlSet; rule "will execute per each Measurement having ID color" no-loop when Measurement( id == "color", $colorVal : val ) then controlSet.add($colorVal); end
The application also includes an empty kmodule.xml which you can use to define the knowledge bases and sessions. This kmodule.xml file, by default, is empty.
<kmodule xmlns="http://www.drools.org/xsd/kmodule"> </kmodule>
This kmodule.xml file, by default, is empty.. Therefore, you can refer to the default ones in your code:
KieBase kBase1 = kContainer.getKieBase(); KieSession kieSession1 = kContainer.newKieSession();
More details about the kmodule.xml structure are available in the product docs: https://docs.jboss.org/drools/release/7.8.0.Final/drools-docs/html_single/index.html#_thekmodulexmlfile
Installing and running the KJAR
To install the KJAR in your Maven repository, you can run the install maven goal:
mvn install
The install goal also executes any Test class available in your project:
2021-12-04 18:06:39,403 INFO [com.sample.RuleTest] (main) Creating kieBase 2021-12-04 18:06:39,404 INFO [org.drools.compiler.kie.builder.impl.KieContainerImpl] (main) Start creation of KieBase: defaultKieBase 2021-12-04 18:06:39,461 INFO [org.drools.compiler.kie.builder.impl.KieContainerImpl] (main) End creation of KieBase: defaultKieBase 2021-12-04 18:06:39,462 INFO [com.sample.RuleTest] (main) There should be rules: 2021-12-04 18:06:39,462 INFO [com.sample.RuleTest] (main) kp [Package name=com.sample] rule will execute per each Measurement having ID color 2021-12-04 18:06:39,462 INFO [com.sample.RuleTest] (main) Creating kieSession 2021-12-04 18:06:39,495 INFO [com.sample.RuleTest] (main) Populating globals 2021-12-04 18:06:39,495 INFO [com.sample.RuleTest] (main) Now running data 2021-12-04 18:06:39,523 INFO [com.sample.RuleTest] (main) Final checks
Deploying a KJAR from the Business Central
The Business Central is a Web application you can use to design and deploy all your assets. ( Check this article to learn more: Getting started with jBPM Business Central .)
Anyhow, you can also design your assets in your IDE and then deploy the artifacts into the Business Central. Once deployed, you can access your assets remotely. Here are the steps:
- Login: http://localhost:8080/business-central/
- Choose the option “Deploy“
- From your Server Configuration choose “Add Deployment Unit“
- Fill the Deployment Unit with Maven GAV settings:
Click Finish and Verify that the asset has been deployed:
Great! Now your Container has been created and you can access your KJAR assets remotely.
The next section shows how to access your Rules using the KieServer client API
Using KIE Server client API to access your assets
Once you have created a Container with your assets, it’s time to use them. The simplest way to do that, is to use the REST API. See this tutorial to learn more: jBPM REST API made simple
As an alternative to REST API, you can also use KIEServer Client API to interact with your KIE containers and business assets
Firstly, include the KIE server dependency (latest version as of 29/11/2021 is 7.62.0 ) in your project:
<dependency> <groupId>org.kie.server</groupId> <artifactId>kie-server-client</artifactId> <version>7.62.0.Final</version> <exclusions> <exclusion> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> </exclusion> </exclusions> </dependency>
Next, add the following Class:
package com.sample; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import org.kie.api.KieServices; import org.kie.api.command.BatchExecutionCommand; import org.kie.api.command.Command; import org.kie.api.command.KieCommands; import org.kie.api.runtime.ExecutionResults; import org.kie.server.api.model.KieContainerResource; import org.kie.server.api.model.KieScannerResource; import org.kie.server.api.model.KieScannerStatus; import org.kie.server.api.model.ReleaseId; import org.kie.server.api.model.ServiceResponse; import org.kie.server.client.KieServicesClient; import org.kie.server.client.KieServicesConfiguration; import org.kie.server.client.KieServicesFactory; import org.kie.server.client.RuleServicesClient; public class KieRestClientBasic { public static final String BASE_URL = "http://localhost:8080/kie-server/services/rest/server"; public static final String GROUP_ID = "com.sample"; public static final String ARTIFACT_ID = "basicKjar"; public static final String VERSION = "1.0-SNAPSHOT"; public static final String CONTAINER_ID = ARTIFACT_ID + "_" + VERSION; public static void main(String[] args) { KieServicesConfiguration config = KieServicesFactory.newRestConfiguration(BASE_URL, "krisv", "krisv"); HashSet<Class<?>> classes = new HashSet<Class<?>>(); classes.add(Measurement.class); config.addExtraClasses(classes); config.setTimeout(1200000); KieServicesClient client = KieServicesFactory.newKieServicesClient(config); ReleaseId releaseId = new ReleaseId(GROUP_ID, ARTIFACT_ID, VERSION); KieContainerResource resource = new KieContainerResource(CONTAINER_ID, releaseId); KieScannerResource scanner = new KieScannerResource(KieScannerStatus.STARTED, 10000L); resource.setScanner(scanner); ServiceResponse<KieContainerResource> response = client.createContainer(CONTAINER_ID, resource); System.out.println(response); Measurement mRed= new Measurement("color", "red"); Measurement mGreen= new Measurement("color", "green"); Measurement mBlue= new Measurement("color", "blue"); RuleServicesClient ruleClient = client.getServicesClient(RuleServicesClient.class); List<Command<?>> commands = new ArrayList<Command<?>>(); KieCommands commandsFactory = KieServices.Factory.get().getCommands(); commands.add(commandsFactory.newInsert(mRed, "fact-" + mRed.toString())); commands.add(commandsFactory.newInsert(mGreen, "fact-" + mGreen.toString())); commands.add(commandsFactory.newInsert(mBlue, "fact-" + mBlue.toString())); commands.add(commandsFactory.newFireAllRules("fire-result")); BatchExecutionCommand batchExecution = commandsFactory.newBatchExecution(commands); ServiceResponse<ExecutionResults> response2 = ruleClient.executeCommandsWithResults(CONTAINER_ID, batchExecution); System.out.println("-----------------------------------"); System.out.println(response2); ExecutionResults result = response2.getResult(); System.out.println(result); ServiceResponse<Void> response3 = client.disposeContainer(CONTAINER_ID); System.out.println(response3); } }
As you can see, we define at first the Server configuration through the KieServicesConfiguration class. Then, we create a Container for our KJAR using the GAV settings of our project.
Please notice that the interaction between the Client and the KieServer is done through the org.kie.server.api.model.ServiceResponse object, which wraps the response from the KieServer.
Finally, we use the org.kie.api.command.KieCommands class to insert commands, and use org.kie.api.KieServices.get().getCommands() to instantiate the KieCommands class. To add multiple commands, it is convenient to use the BatchExecutionCommand wrapper.
When your Batch execution has completed, we use the disposeContainer method to dispose the asset from the KieServer.