We have a Java application with different modules being deployed on Weblogic. We are using drools on different modules and tried to make the class that initializes the KieContainer a singleton by defining it as an enum class.
However, it seems that when we are in the production environment (where the application is deployed through a ear file) there are different ClassLoaders initializing this class and we get the following exception:
null java.lang.IllegalStateException: There's already another KieContainer created from a different ClassLoader;
at org.drools.compiler.kie.builder.impl.KieServicesImpl.getKieClasspathContainer(KieServicesImpl.java:88);
at org.drools.compiler.kie.builder.impl.KieServicesImpl.getKieClasspathContainer(KieServicesImpl.java:73);
Do you have any suggestion on how to solve this?
We had the same problem though in a different environment (Kafka, Weld SE). Though counter-intuitive, invoking
// Answer the cuurent container if it exists else create a new container
KieServices.Factory.get().getKieClasspathContainer();
not
// Always create a new container
KieServices.Factory.get().newKieClasspathContainer();
fixed most things for us.
Also, before the container goes out of scope be sure to invoke:
KieServices.Factory.get().getKieClasspathContainer().dispose();
This will release the container and its resources from the Drools global singleton.
We also had problems running unit tests in Maven as the Surefire plugin by default does not recreate a JVM per test while Drools assumes that an instance of its global singleton will be created just once per JVM invocation. This is resolved by having Surefire recreate a clean JVM environment per test. Adjust your pom.xml by adding
<reuseForks>false</reuseForks>
to your Surefire configuration. For example:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>default-test</id>
<configuration>
<reuseForks>false</reuseForks>
</configuration>
</execution>
</executions>
</plugin>
Also, you might consider assigning each Java EE module its own KieContainer
KieContainer getKieClasspathContainer(String containerId);
This would allow the lifecycle of each Java EE module to be synchronised to that of each Drools container module.
The drools code checks if your specified class loader and the current instance this.getClass().getClassLoader() is the same, if not errors out with the KieContainer already exists eror . If you dont specify a classloader it uses Thread.currentThread().getContextClassLoader() , which is different from this.getClass().getClassLoader() in some situvations. Simple solution is to use KieServices.Factory.get().getKieClasspathContainer(this.getClass().getClassLoader())
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With