I have embedded DROOLS 8 engine in a simple standalone app for testing.
So far I was able to instantiate a KIE session, load and build a DRL file from disk.
If the DRL is a simple rule files, it works out of the box, when I try to implement a RuleUnit by DRL file (as in the guide https://docs.drools.org/8.44.0.Final/drools-docs/drools/language-reference/index.html#con-drl-rule-units_drl-rules)
package org.mortgages;
unit MortgageRules;
import org.drools.ruleunits.api.RuleUnitData;
import org.drools.ruleunits.api.DataStream;
import org.drools.ruleunits.api.DataSource;
declare Person
name : String
dateOfBirth : String
address : String
end
declare MortgageRules extends RuleUnitData
persons: DataStream<Person>
end
rule "Using a rule unit with a declared type"
when
$p : /persons[ name == "James" ]
then // Insert Mark, who is a customer of James.
Person mark = new Person();
mark.setName( "Mark" );
persons.append( mark );
end
then I have an error, when it reaches the part of persons.append
and the error is:
java.lang.NullPointerException: Cannot invoke "org.drools.ruleunits.api.DataStream.append(Object)" because "persons" is null
If the same class MortgageRules
is provided by a java class implementation (handwritten in code)
public class MortgageRules implements RuleUnitData {
@Getter
private final DataStream<Person> persons = DataSource.createStream();
}
it works! seems like buildAll
is not generating/instantiating the RuleUnitData piece of code.
Main is
KieServices ks = KieServices.Factory.get();
KieRepository kr = ks.getRepository();
KieFileSystem kfs = ks.newKieFileSystem();
drlStream = ClassLoader.getSystemClassLoader().getResourceAsStream("mortgage.drl");
kfs.write("src/main/resources/KBase1/mortgage.drl", ks.getResources().newInputStreamResource(drlStream));
KieBuilder kb = ks.newKieBuilder(kfs);
kb.buildAll(); // kieModule is automatically deployed to KieRepository if successfully built.
if (kb.getResults().hasMessages(Message.Level.ERROR)) {
throw new RuntimeException("Build Errors:\n" + kb.getResults().toString());
}
KieContainer kContainer = ks.newKieContainer(kr.getDefaultReleaseId());
KieSession kSession = kContainer.newKieSession();
var eps = kSession.getEntryPoints();
var eventsStream = kSession.getEntryPoint("DEFAULT");
// Thread pushing Person instances in eventsStream
kSession.fireUntilHalt();
Firstly, if you want to use RuleUnit, you need to use RuleUnit APIs, which you can start with the archetype example https://docs.drools.org/8.44.0.Final/drools-docs/drools/getting-started/index.html#first-rule-project_getting-started
Your Main class uses traditional APIs, so you would need to use traditional DRL syntax instead of RuleUnit. Unfortunately, the Drools 8 document doesn't have a chapter for "traditional DRL syntax", but it's fully supported. To learn the traditional DRL syntax, please refer to the Drools 7 docs (https://docs.drools.org/7.74.1.Final/drools-docs/html_single/#drl-rules-con_drl-rules). We plan to bring back the traditional DRL syntax chapter to the new version documentation. Sorry for your inconvenience.
Secondary, the DRL declared Rule Unit is a bit tricky. Indeed, Drools 8 has a capability of generating RuleUnit java class by "declare", but it's meaningful only when you also auto-generate the application java code to use the generated RuleUnit, because the class doesn't exist until the project is built by maven. Such a use case can be found in drools-quarkus integration which also generates REST endpoint (https://github.com/apache/incubator-kie-drools/blob/main/drools-quarkus-extension/drools-quarkus-ruleunit-integration-test/src/main/resources/org/drools/quarkus/ruleunit/test/AlertingService.drl). I filed an issue to improve the document : https://github.com/apache/incubator-kie-drools/issues/5752
Having said that, the guidance would be
A) If you want to use RuleUnit with Quarkus and rely on auto generated REST endpoints, follow the drools-quarkus integration approach.
B) If you want to use RuleUnit without Quarkus or not rely on auto generated REST endpoints, write Rule Unit java class instead of "declare". Also please make sure to use RuleUnit APIs.
C) If you are fine with the traditional DRL syntax, use the traditional DRL syntax instead of Rule Unit. In this case, you can keep using the traditional APIs like the Main code.