Drools Rule Engine - Multiple .drl file for different set of rules for different context - jboss

I am using spring boot drools. I would like to maintain say 3 different drl files for different context as the rules are different for different context. In this case should I create 3 key KieContainer for each context or is it possible to handle in just on kie container? Note: for each context I have to invoke only the corresponding drl rules
#Bean
public KieContainer getKieContainer() {
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
kieFileSystem.write(ResourceFactory.newFileResource("ctxt1.drl")));
kieFileSystem.write(ResourceFactory.newFileResource("ctxt2.drl")));
KieBuilder kb = kieServices.newKieBuilder(kieFileSystem);
kb.buildAll();
KieModule kieModule = kb.getKieModule();
KieContainer kieContainer = kieServices.newKieContainer(kieModule.getReleaseId());
return kieContainer;
}
this is how I invoke rule. Here I would like to invoke context based drl file rules in the session.
How to use KieBase based KieSession?
KieSession kieSession = kieContainer.newKieSession();
kieSession.insert(RequestPOJO);
kieSession.fireAllRules();
kieSession.dispose();

Based on the limited description, sounds like "different context" can be identified with a Knowledge Base (KieBase).
You can create 1 KJAR with the 3 different DRL files, making sure (e.g.: via package) they correspond to 3 different KieBases.
Something ~like:
<kmodule>
<kbase name="KBase1" packages="org.acme,org.context1" />
<kbase name="KBase2" packages="org.acme,org.context2" />
<kbase name="KBase3" packages="org.acme,org.context3" />
...
</kmodule>
Then you could create 1 KieContainer, which contains the single KJAR containing the "multiple contexts" (KieBases).
At that point, from the KieContainer, you can create a KieSession with the specific KieBase you want.

Related

How to ensure if drl file is loaded by KIE

Is there any quick way to check programmatically if DRL file is loaded successfully by the drools library within our web application? BTW, I am developing soap based web service using drools. For ex: listing out all the rule names present in the knowledge base at a certain time etc.
Please help.
This is what I am doing to load the drl file from centOS filesystem:
String drlFile = "/tmp/conf/object.drl";
ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem();
FileInputStream fis = new FileInputStream( drlFile );
kfs.write("/Drools/Object.drl",ks.getResources().newInputStreamResource( fis ));
KieBuilder kieBuilder = ks.newKieBuilder( kfs ).buildAll();
The simplest way to detect errors on a build all is to pull up the messages on the results from the buildAll().
kieBuilder.getResults().hasMessages(Message.Level.ERROR)
or
kieBuilder.getResults().getMessages()
as a side note*
I had a similar issue where buildAll() was not reading the file I wrote inside the kfs. The symptoms were the same where no packages were in the collection.
To fix that issue I had to add a specific resource type to the inputStream.
e.g.
kfs.write("/Drools/Object.drl",ks.getResources().newInputStreamResource( fis ).setResourceType(ResourceType.DRL));
For determining the packages inside the ksession I always have used.
ksession.getKieBase().getKiePackages()
For detecting the files my builder knew about and loaded I used this
((MemoryKieModule)kb.getKieModule()).getFileNames()

JBoss Drools - how to get data (facts) from java to DRL

How can I get fact definied by user in GUI and insert it to DRL?
For example: The user has chosen black car in GUI (JavaFX), and now I want to use that fact in DRL code. How to send that info about black car to DRL? Should i use POJO?
If you want to execute rules that you have written in DRL file you have to create a POJO and using KieSession you can execute your rules. For example,
val pojo = new POJO('POJO arguments')
val kieServices = KieServices.Factory.get()
val kieContainer = kieServices.newKieClasspathContainer()
val kieSession = kContainer.newKieSession()
kieSession.insert(pojo)
kieSession.fireAllRules()
Read this documentation. You can get all the drool-API examples here

Get KieSession and KieServices in Optaplanner

I want to create an Audit logger for the rules i have in my OptaPlanner project
and i need to get access to KieSession and KieServices from Drools to do that.
The problem here is i don't have access to them.
In the documentation in section 5.3.4.2.3. A ksessionName in a Kjar from a Maven repository, i can define a KieSessionName from the solverConfig and create the SolverFactory using the createFromKieContainerXmlResource. The problem here is that i can't find the META-INF/kmodule.xml file. Even if i find the folder, can i use the KieSessionName to get a KieSession.
I'm asking this because with the current way of creating the SolverFactory, using createFromXmlResource, i can get to the KieSessionName with using:
SolverConfig solverConfig = solverFactory.getSolverConfig();
ScoreDirectorFactoryConfig scoreDirectorFactoryConfig = solverConfig.getScoreDirectorFactoryConfig();
String kieSessionName = scoreDirectorFactoryConfig.getKsessionName();
After getting the session name i can't find a way to get the KieSession.
So my questions here are:
Where can i locate META-INF/kmodule.xml?
How can i use kSessionName to get use as a KieSession object?
Is there a way to access the KieSession object without chaging the core files?

Drools rules not firing from Akka actor system

We've built a Drools module in Scala which runs just fine when called separately, however now we're integrating it into an Akka actor system we've built to be able to fire rules via REST calls.
For some reason no rules are firing whatsoever, even blank rules such as:
rule "sample 1"
salience 1000
auto-focus true
when
then
System.out.println("Well, that finally worked!");
end
The KieContainer, Session etc. seem to be fine and the objects (facts) are being inserted correctly (verified by checking the Fact Count). (The KieServices and KieContainer are being initialised at boot level, i.e. before the actors are created, and used at a later stage.) The strange thing is that when running kieSession.fireallrules() the total number of rules fired is always 0 and the facts aren't updated.
Using Akka, we're sending an object (of type MyObject) in JSON format via REST. An actor is created per REST request and calls the Drools module as below:
A new actor is created to call the Drools Engine.
A new KieSession is created using the KieServices set at Boot level. [For those who've seen my previous posts, yes the following is Scala code]
val kieSession = DroolsMgt.getKieSession(List("myFile.drl"), Boot.kieServices)
where getKieSession is calling the following:
val kfs = kieServices.newKieFileSystem()
for (filename <- drlFiles) {
val fis = new FileInputStream(filename)
kfs.write(filename, kieServices.getResources.newInputStreamResource(fis))
}
val kieBuilder = kieServices.newKieBuilder(kfs).buildAll()
val kieContainer = kieServices.newKieContainer(kieServices.getRepository.getDefaultReleaseId)
kieContainer.newKieSession()
The object received via REST (which is extracted from the JSON format) is then loaded into Drools Memory via ksession.insert(testObject) and the object's FactHandle is saved
The rules are then fired and the updated object is returned using its FactHandle as follows:
ksession.fireAllRules()
val getObject = ksession.getObject(myObjectFH)
ksession.dispose()
getObject.asInstanceOf[MyObject]
As before, this works when running the Drools Module on its own but not when using the actor system as above. I've even tried firing empty rules and printing text out onto the screen for debugging purposes but literally no rules are being fired. I am sure I'm calling the right DRL file and the right KieSession but can't figure out what's going wrong here. (Is there any way to check the number of rules in a KieSession?)
Any ideas?
EDIT:
After looking into laune's suggestion I found that there weren't any KiePackages being loaded into the KieBase. I've narrowed this down to the files not being loaded as KieResources at kfs.write("src/main/resources/testFile.drl", kieServices.getResources().newInputStreamResource(fis))
Any idea what might be causing this?
For reference, I'm loading DRL files into the KieContainer and creating the KieSession (successfully) as follows:
val kieServices = KieServices.Factory.get()
val kfs = kieServices.newKieFileSystem()
val fis = new FileInputStream("src/main/resources/testFile.drl")
kfs.write("src/main/resources/testFile.drl", kieServices.getResources().newInputStreamResource(fis))
val kieBuilder = kieServices.newKieBuilder(kfs).buildAll()
val results = kieBuilder.getResults()
if (results.hasMessages(Message.Level.ERROR)) {
throw new RuntimeException(results.getMessages().toString())
}
val kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId())
kieContainer.newKieSession()
The following code will not fix your problem but it should help you diagnose whether you really run the rules and the session you think you do. I'm using Java notation.
KieSession kieSession = ...
KieBase kieBase = kieSession.getKieBase();
Collection<KiePackage> kiePackages = kieBase.getKiePackages();
for( KiePackage kiePackage: kiePackages ){
for( Rule rule: kiePackage.getRules() ){
System.out.println( rule.getName() );
}
}

Getting a handle of POJOs inside my kjar

I just set up a kie-workbench (6.1.0 Final) on tomcat and created an example demo-project which contains a drl file and a big flat POJO created with the data modeller.
I built and deployed the demo-project and managed to fire the rules from a client application using the code below:
String url = "http://yytomcat7kie.domain.com:8080/kie/maven2/gro/up/demoproject/0.0.3/demoproject-0.0.3.jar";
ReleaseIdImpl releaseId = new ReleaseIdImpl("gro.up", "demoproject", "0.0.3");
KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem();
UrlResource urlResource = (UrlResource) ResourceFactory.newUrlResource(url);
kfs.write(urlResource);
KieBuilder kieBuilder = ks.newKieBuilder(kfs).buildAll();
KieContainer kContainer = ks.newKieContainer(releaseId);
KieSession kSession = kContainer.newKieSession();
SessionConfiguration sConf = (SessionConfiguration)kSession.getSessionConfiguration();
MyKiePojo kiePojo = new MyKiePojo();
kiePojo.setField01("blah");
kiePojo.setField02("blahblah");
kiePojo.setField03("blahblahblah");
kSession.insert(kiePojo);
kSession.fireAllRules();
System.out.println(" ALL RULES FIRED ");
System.out.println(kiePojo.getField04());
System.out.println(kiePojo.getField05());
It works fine but the question I have now is:
Is it possible to get a handle of the MyKiePojo class which is in the demoproject.jar without having it in the client app's classpath? Ideally I would like to keep all my models in the workbench without having to mirror them in the client app and be able to instantiate them and populate them with values received from rest requests. Is this possible?
A KieContainer when used with dynamic modules keeps all the jars it loads in an isolated ClassLoader. So you can put your models into their own jar and specify them as a maven dependency on the project being deployed. If you are using kie-ci it will resolve the transitive dependencies and build a ClassLoader from them.
Externally you can use reflection to access the pojos in that CassLoader, or you can have an initialisation rule that calls out to a static initialisation method. Where that static initializer method is any class in the jar or one of the dependant jars.
What we don't have yet is a life cycle for KieContainers and KieSession to automate certain things via callbacks. This is definitely something we need to look into, and I expect it to be in the next (after 6.2) release.
See the documentation chapter "Rule Language Reference", section "Type Declaration". A quick example taken from there:
declare Address
number : int
streetName : String
city : String
end
You can create objects using new and use getters and setters etc.
You'll have to code the transformation from the request to this object.