如何在运行时使drools drl文件访问更新的jar

时间:2011-05-17 15:37:41

标签: java drools

最近我正在研究一个drools项目,我遇到了一些问题,我需要一些帮助。 在我的项目中,我通过使用URLClassLoader在运行时访问jar.Here是代码:

Object object=null;
 Class myclass=null;
 URL jarPath=null;
 try{
    jarPath=new File("lib/Billing.jar").toURI().toURL();
    URLClassLoader loader = new URLClassLoader(new URL[] { jarPath },ClassLoader.getSystemClassLoader());
    ruleclass = loader.loadClass("dynamicclasses.Billing");
    object = ruleclass.newInstance();                       
}
catch (Exception e) {e.printStackTrace}

获取类实例后,我将设置值并将对象传递给我的drools类

new DroolsClass().fireRules(object);

drools类包含以下代码:

public class DroolsClass {
public void fireRules(Object object){   
        try {
            KnowledgeBase kbase = readKnowledgeBase();
            StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
            KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");
            ksession.insert(object);
            ksession.fireAllRules();                    
            logger.close();

        } catch (Throwable t) {
            t.printStackTrace();    
        }

}
private static KnowledgeBase readKnowledgeBase() throws Exception {

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add(ResourceFactory.newFileResource("./rulefiles/testing.drl"), ResourceType.DRL);
            KnowledgeBuilderErrors errors = kbuilder.getErrors();
        // ------ some code
        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
        return kbase;
}

接下来我有一个drl文件testing.drl,该文件存在于directoty文件中,它访问了Billing.jar中存在的相同类dynamicclasses.Billing

这是drl文件内容:

import dynamicclasses.Billing;

rule "rule 3"

salience 10 
dialect "mvel" 
no-loop true
when
     m : Billing(bplan=="plan1")
then
    System.out.println("You have opted for plan1");   
end

我遇到的问题是jar,即Billing.jar在运行时更新drl文件,即testing.drl 无法访问更新的jar。

我正在努力做以下事情。

1)我将在运行时创建jar并在需要时更新它。 2)我将在运行时创建一个drl文件,它将导入jar中存在的类,即dynamicclasses.Billing

我可以使用URLClassLoader访问我的java类中更新的jar内容。但是一旦我将对象传递给我的drools类,我得到以下异常

Unable to resolve ObjectType 'Billing' : [Rule name='rule 3']

Error importing : 'dynamicclasses.Billing'
java.lang.IllegalArgumentException: Could not parse knowledge.

如果我重启我的应用程序,我没有异常,因为jar已经存在,但是对象似乎没有传递给drl而且我没有得到任何结果。

我对代码进行了以下更改:

URLClassLoader loader = new URLClassLoader(new URL[] { jarPath },this.getClass().getClassLoader());

这里我最初得到了同样的例外。但是在我重新启动我的应用程序之后它运行正常并且规则被触发了,我将得到结果。

但是,如果我更新jar,它将只访问以前的内容。

因此很清楚,drl文件无法在更新后进行初始访问。 有什么方法可以让它发挥作用吗?

感谢。

3 个答案:

答案 0 :(得分:2)

谢谢:)最后我能够解决这个问题。您需要将自定义类加载器不仅传递给KnowledgeBuilderConfiguration,还要传递给KnowledgeBaseConfiguration,以使您的知识库能够了解您的自定义类加载器。

private static KnowledgeBase readKnowledgeBase(ClassLoader loader) throws Exception {

        KnowledgeBuilderConfiguration kBuilderConfiguration = KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration(null, loader);
        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(kBuilderConfiguration);

        KnowledgeBaseConfiguration kbaseConfig = KnowledgeBaseFactory.newKnowledgeBaseConfiguration(null, loader);

        kbuilder.add(ResourceFactory.newFileResource("./rulefiles/testing.drl"), ResourceType.DRL);
        KnowledgeBuilderErrors errors = kbuilder.getErrors();

        if (errors.size() > 0) {
            for (KnowledgeBuilderError error: errors) {
                System.err.println(error);
            }
            throw new IllegalArgumentException("Could not parse knowledge.");
        }

        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(kbaseConfig);
        kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
        return kbase;
    } 

答案 1 :(得分:1)

您可以尝试使用KnowledgeBuilderConfiguration传递KnowledgeBuilder的类加载器。

ClassLoader loader = new URLClassLoader(
    new URL[] { jarPath },
    ClassLoader.getSystemClassLoader());
KnowledgeBuilderConfiguration kBuilderConfiguration 
    = KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration(null, loader);
KnowledgeBuilder kbuilder 
    = KnowledgeBuilderFactory.newKnowledgeBuilder(kBuilderConfiguration);

答案 2 :(得分:0)

对于Drool 6.5.0,可以通过以下方式添加类加载器:

kieServices = KieServices.Factory.get();

KieFileSystem kieFileSystem = kieServices.newKieFileSystem();        
kieFileSystem.write("./rulefiles/testing.drl", drl);
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem, loader);
kieBuilder.buildAll();

KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId(), 
            pluginCtxObject.getClass().getClassLoader());
StatelessKieSession statelessKieSession = kieContainer.getKieBase().newStatelessKieSession();
statelessKieSession.execute(object);