Skip to content
Advertisement

Drools KieContainer does not fire rules with custom classloader

I am trying to add a non-existing method to a Java bean, compile it and use the newly added method in Drools rules. Via a custom class loader.

I am using CompilerUtils to bind newly modified class to the custom ClassLoader as follows:

        ClassLoader loader = new ClassLoader(){};

        String className = "com.example.Transaction";

        String path = "file:D:/workspace/Transaction.class.tmp"; // a tmp file that contains source for Java bean

        try {

            URL transactionUrl = new URL(path);

            URLConnection connection = transactionUrl.openConnection();

            InputStream input = connection.getInputStream();

            String transactionClass = new String(StreamUtils.copyToByteArray(input), StandardCharsets.UTF_8);

            System.out.println(transactionClass);

            String javaCode = "npublic int test() {n" +
                    "        return 3;n" +
                    "    }n" +
                    "}";

            String updatedClassString = transactionClass.substring(0, transactionClass.length() - 1).concat(javaCode);

            Class<?> classB = CompilerUtils.CACHED_COMPILER.loadFromJava(loader, className, updatedClassString); // This is where the loader is made aware of the newly compiled class
            
            return loader;


        } catch (IOException | ClassNotFoundException exception) {
            e.printStackTrace();
        }

        return null;

And this is where I give access to drools my classloader

   
        final KieServices kServices = KieServices.Factory.get();
        final KieFileSystem kFileSystem = kServices.newKieFileSystem();

        final KieModuleModel kModuleModel = KieRulePopulator.kieModuleModel();
        if (kModuleModel != null) kFileSystem.writeKModuleXML(kModuleModel.toXML());

        kServices
                .newKieBuilder(kFileSystem, classLoader)
                .buildAll();
        }

        KieContainer container = kServices.newKieContainer(kServices
                .getRepository()
                .getDefaultReleaseId(), classLoader);

This is how I fire rules

       final KieBaseConfiguration configuration = KieServices.Factory.get().newKieBaseConfiguration();

       final KieSession kSession = container
                .getKieContainer()
                .newKieBase(configuration)
                .newKieSession();

Transaction someTransaction = new Transaction();

kSession.insert(transaction);
kSession.fireAllRules();
    

And this is my rule

    rule "Rule_31F6DE769554404B89D4E3B7B5979CA1"
    dialect "java"
    no-loop true
    
    when
        tr : Transaction( test == 3 )

    then
        System.out.println("deneme");
    end

Advertisement

Answer

I have load Transaction class from containers classloader and it worked.

final KieSession kSession = container
                .getKieContainer()
                .newKieBase(configuration)
                .newKieSession();

Class<?> classA = container.getKieContainer().getClassLoader().loadClass("com.example.Transaction");

Object transaction = classA.getDeclaredConstructor().newInstance();

kSession.insert(transaction);
kSession.fireAllRules();
Advertisement