Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drools KieContainer from different ClassLoader

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?

like image 764
João Almeida Avatar asked Jul 06 '17 13:07

João Almeida


2 Answers

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.

like image 199
Steve Brewin Avatar answered Oct 12 '22 00:10

Steve Brewin


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())

like image 26
Param Natarajan Avatar answered Oct 12 '22 01:10

Param Natarajan