João Almeida
João Almeida

Reputation: 5077

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?

Upvotes: 6

Views: 2986

Answers (3)

jim owens
jim owens

Reputation: 51

Personally, I think the solution is to transition to using the KieRuntimeBuilder, which generates a session through the following code:

kieRuntimeBuilder.newKieSession();

At the end, you can dispose of it, but another option I haven't looked into could be to define a class implementing the KieContainer or KieSession, but who knows where that trail leads.

Upvotes: 0

Param Natarajan
Param Natarajan

Reputation: 11

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

Upvotes: 1

Steve Brewin
Steve Brewin

Reputation: 231

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.

Upvotes: 3

Related Questions