I am upgrading a drools project from an ancient version to 9.44 because it's recommended here: https://www.baeldung.com/drools-excel.
I have written a unit test to verify my rules classes and make sure that the new setup is going to work. Here is my function under test.
/**
* From a decision table, create a KIE container
* @param is the input stream to read
* @return a kie container
*/
public static KieContainer getKieContainerFromStream(InputStream is){
KieServices kieServices = KieServices.Factory.get();
Resource resource = ResourceFactory.newInputStreamResource(is);
KieFileSystem kieFileSystem = kieServices.newKieFileSystem().write(resource);
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
kieBuilder.buildAll();
KieRepository kieRepository = kieServices.getRepository();
ReleaseId krDefaultReleaseId = kieRepository.getDefaultReleaseId();
KieContainer result = kieServices.newKieContainer(krDefaultReleaseId);
return result;
}
and then I wrote a unit test to begin walking through the code:
InputStream is = getClass().getClassLoader().getResourceAsStream(POSTPONE_RULES);
KieContainer kieContainer = DroolsUtil.getKieContainerFromStream(is);
This test crashes because KieServices.Factory.get()
returns null.
After thinking about this for a while, I pulled the example code and it starts with:
KieContainer kc = KieServices.Factory.get().getKieClasspathContainer();
and it is not blowing up with a NPE on the call to getKie...so it's not returning null.
Hmm. Exactly the same code and different results???
Also, I found other questions without answers like: Drools - KieServices.Factory.get() returns null
So after some head-scratching, I began to wonder if the problem was the unit test class path itself.
So it occurred to me to go into the examples project and drop my util method right next to the working example above and then create a unit test there and run it and see what happens.
Answer: It returned null from Factory.get()
Hmmm...Maybe it's a difference with unit tests. So I create a new unit test for the PricingRuleDTExample out of drools. First, I retool the example a little:
/**
* This shows off a decision table.
*/
public class PricingRuleDTExample {
public static final void main(String[] args) {
KieContainer kc = getContainer();
System.out.println(kc.verify().getMessages().toString());
execute( kc );
}
public static KieContainer getContainer() {
KieContainer result = KieServices.Factory.get().getKieClasspathContainer();
return result;
}
public static void execute( KieContainer kc ) {
StatelessKieSession ksession = kc.newStatelessKieSession( "DecisionTableKS");
//now create some test data
Driver driver = new Driver();
Policy policy = new Policy();
ksession.execute( Arrays.asList(driver, policy));
System.out.println( "BASE PRICE IS: " + policy.getBasePrice() );
System.out.println( "DISCOUNT IS: " + policy.getDiscountPercent() );
policy.getBasePrice();
}
}
Then I create a unit test:
public class PricingRuleDTExampleTest {
@Before
public void setUp() throws Exception {
}
@Test
public void getContainer() {
assertNotNull(PricingRuleDTExample.getContainer());
}
}
and it works perfectly. ????
OK, this is not funny anymore.
So, running in the drools-example environment against 9.44, I rework my method just to see what will happen:
public static KieContainer getKieContainerFromStream(InputStream is){
KieContainer result = KieServices.Factory.get().getKieClasspathContainer();
// KieServices kieServices = KieServices.Factory.get();
// Resource resource = ResourceFactory.newInputStreamResource(is);
// KieFileSystem kieFileSystem = kieServices.newKieFileSystem().write(resource);
// KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
// kieBuilder.buildAll();
// KieRepository kieRepository = kieServices.getRepository();
// ReleaseId krDefaultReleaseId = kieRepository.getDefaultReleaseId();
// KieContainer result = kieServices.newKieContainer(krDefaultReleaseId);
return result;
}
and it returns successfully.
My head spins...how does adding a method call to the return value make Factory.get() return a value instead of null?
Can someone please review what I've done and show me where I missed it?
The issue turned out to be a classpath problem. I added drools-compiler to the classpath and it fixed it.
Kie/Drools uses a number of these factory methods that simply return null if an implementing class is not found on the classpath. It would be nice if these threw an exception with a better explanation instead of simply returning null.