Thursday, October 31, 2013

Configuration and Convention based Building and Utilization

Sneak peak at some of the 6.0 documentation we are writing. This introduces, via examples, the new ways to work with DRL and BPM2 files - without needing to programmatically create a builder, load resources.

Enjoy
--
6.0 introduces a new configuration and convention approach to building knowledge bases, instead of the using the programmatic builder approach in 5.x. Atlhough a builder is still available to fall back on, as it's used for the tooling integration.
Building now uses Maven, and aligns with Maven practices. A KIE projcet or module is simply a Maven java project or module; with an additional meta data file META-INF/kmodule.xml. The kmodule.xml file is the descriptor that selects resources to knowledge bases and configures those knowledge bases and sessions. There is also alternative xml support via Spring and OSGi BluePrints.
While standard Maven can build and package KIE resources, it will not provide validation at build time. There is a Maven plugin which is recommend to use to get build time validation. The plugin also pre-genenerates many classes, making the runtime loading faster too.

Maven can either 'mvn install' to deploy a KieModule to the local machine, where all other applications on the local machine use it. Or it can 'mvn 'deploy' to push the KieModule to a remote Maven repository. Building the Application wil pull in the KieModule, popualting it's local Maven repository, as it does so.

Jars can be deployed in one of two ways. Either added to the classpath, like any other jar in a Maven dependency listing, or they can be dynamically loaded at runtime. KIE will scan the classpath to find all the jars with a kmodule.xml in it. Each found jar is represented by the KieModule interface. The term Classpath KieModules and dynamic KieModule is used to refer to the two loading approaches. While dynamic modules supports side by side versioning, classpath modules do not. Further once module is on the classpath, no other version may be loaded dynamically.
Detailed referencs for the api are included in the next sections, the impatiant can jump straight to the examples section, which is fairly intuitive for the different use cases.

The best way to learn the new build system is by example. The source project "drools-examples-api" contains a number of examples, and can be found at github:
https://github.com/droolsjbpm/drools/tree/6.0.x/drools-examples-api
Each example is described below, the order starts with the simplest and most default working it's way up to more complex use cases.
The Deploy use cases here all involve mvn install. Remote deployment of jars in Maven is well covered is Maven literature. Utilize refers to the initial act loading the resources and providing access to the KIE runtimes. Where as Run refers to the act of interacting with those runtimes.

kmodule.xml will produce a single named KieBase, 'kbase2' that includes all files found under resources path, be it DRL, BPMN2, XLS etc. Further it will include all the resources found from the KieBase 'kbase1', due to the use of the 'includes' attribute. KieSession 'ksession2' is associated with that KieBase and can be created by name.

This example requires that the previous example, 'named-kiesession', is built and installed to the local Maven repository first. Once installed it can be included as a dependency, using the standard Maven element.

Once 'named-kiesession' is built and installed this example can be built and installed as normal. Again the act of installing, will force the unit tests to run, demonstrating the use case.

ks.getKieClasspathContainer() returns the KieContainer that contains the KieBases deployed onto the environment classpath. This time the KieSession uses the name 'ksession2'. You do not need to lookup the KieBase first, as it knows which KieBase 'ksession1' is assocaited with. Notice two rules fire this time, showing that KieBase 'kbase2' has included the resources from the dependency KieBase 'kbase1'.
kmodule.xml produces 6 different named KieBases. 'kbase1' includes all resources from the KieModule. The other KieBases include resources from other selected folders, via the 'packages' attribute. Note the use wildcard '*' use, to select this package and all packages below it.


Only part of the example is included below, as there is a test method per KieSession, but each one is a repetitino of the other, with just different list expectations.
The pom.xml must include kie-ci as a depdency, to ensure Maven is available at runtime. As this uses Maven under the hood you can also use the standard Maven settings.xml file.


In the previous examples the classpath KieContainer used. This example creates a dynamic KieContainer as specified by the ReleaseId. The ReleaseId uses Maven conventions for group id, artifact id and version. It also obey's LATEST and SNAPSHOT for versions.
No kmodue.xml file exists. The projects 'named-kiesession' and 'kiebase-include' must be built first, so that the resulting jars, in the target folders, be be reference as Files.

Creates two resources. One is for the main KieModule 'exRes1' the other is for the dependency 'exRes2'. Even though kie-ci is not present and thus Maven is not there to resolve the dependencies, this shows how you can manually specify the dependency KieModuels, for the vararg.

This programmatically builds a KieModule. It populates the model that represents the ReleaseId and kmodule.xml, as well as added the resources tht. A pom.xml is generated from the ReleaseId.
Example 2.59. Utilize and Run - Java
KieServices ks = KieServices.Factory.get();

KieFileSystem kfs = ks.newKieFileSystem();


Resource ex1Res = ks.getResources().newFileSystemResource(getFile("named-kiesession"));

Resource ex2Res = ks.getResources().newFileSystemResource(getFile("kiebase-inclusion"));


ReleaseId rid = ks.newReleaseId("org.drools", "kiemodulemodel-example", "6.0.0-SNAPSHOT");

kfs.generateAndWritePomXML(rid);


KieModuleModel kModuleModel = ks.newKieModuleModel();

kModuleModel.newKieBaseModel("kiemodulemodel")

            .addInclude("kiebase1")

            .addInclude("kiebase2")

            .newKieSessionModel("ksession6");


kfs.writeKModuleXML(kModuleModel.toXML());

kfs.write("src/main/resources/kiemodulemodel/HAL6.drl", getRule());


KieBuilder kb = ks.newKieBuilder(kfs);

kb.setDependencies(ex1Res, ex2Res);

kb.buildAll(); // kieModule is automatically deployed to KieRepository if successfully built.

if (kb.getResults().hasMessages(Level.ERROR)) {

    throw new RuntimeException("Build Errors:\n" + kb.getResults().toString());

}


KieContainer kContainer = ks.newKieContainer(rid);


KieSession kSession = kContainer.newKieSession("ksession6");

kSession.setGlobal("out", out);


Object msg1 = createMessage(kContainer, "Dave", "Hello, HAL. Do you read me, HAL?");

kSession.insert(msg1);

kSession.fireAllRules();


Object msg2 = createMessage(kContainer, "Dave", "Open the pod bay doors, HAL.");

kSession.insert(msg2);

kSession.fireAllRules();


Object msg3 = createMessage(kContainer, "Dave", "What's the problem?");

kSession.insert(msg3);

kSession.fireAllRules();