Getting started with KJar archives

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:

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:
what is a kjar

Click Finish and Verify that the asset has been deployed:

introduction to kjar

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.

Found the article helpful? if so please follow us on Socials