从 Drools 6.0.1 迁移到 Drools 6.3.0-Final 出现意外的全局 [log] 错误

Migrating from Drools 6.0.1 to Drools 6.3.0-Final got Unexpected global [log] error

java.lang.RuntimeException: Unexpected global [log]
at org.drools.core.impl.StatefulKnowledgeSessionImpl.setGlobal(StatefulKnowledgeSessionImpl.java:1163)
  1. DRL 作为字符串列表从数据库中检索。
  2. 我们不使用 kmodule.xml 关注评论: DRL(最小化设置以尝试找到问题)加载顺利,但不知何故其中定义的全局变量不是。

KieSession 创建代码

 KieServices ks = KieServices.Factory.get();
        KieRepository kr = ks.getRepository();
        KieFileSystem kFileSystem = ks.newKieFileSystem();

        int i=0;
        for (String ruleId : drls.keySet()){
            Resource resource = ks.getResources().newByteArrayResource(drls.get(ruleId).getBytes());
            resource.setTargetPath("./out/"+ ruleId +".drl");
            resource.setResourceType(ResourceType.DRL);
            kFileSystem.write(resource);
        }
        KieBuilder kieBuilder = ks.newKieBuilder( kFileSystem );
        kieBuilder.buildAll();
    KieBuilder kieBuilder = ks.newKieBuilder( kFileSystem );
    kieBuilder.buildAll();
    if (kieBuilder.getResults().hasMessages(Message.Level.ERROR)) {
        log.error(PolicyUtils.createMsg("DRL Errors:\n" + kieBuilder.getResults().toString()), context, null, null);
        throw new RuntimeException("DRL Errors:\n" +         kieBuilder.getResults().toString());
    }
    kContainer = ks.newKieContainer(kr.getDefaultReleaseId());
    kContainer.newKieSession();

在你的Java代码中你有一些像

这样的调用
kieSession.setGlobal( "log", ... );

在您的 .drl 文件中应该有对应的文件,例如

global ... log;

但它没有。 (圆点分别标记对象引用和相应类型的位置。)

正在查看您的代码...

kFileSystem.write(resource);

我强烈建议您使用具有以下相对路径的表单:

kFileSystem.write( "src/main/resources/" + ruleId + ".drl,
                   resource );

或修改资源目标路径:

resource.setTargetPath("src/main/resources/hello.drl");

(您的代码工作:

resource.setTargetPath("./out/hello.drl");

稍后,在编译期间,这会导致警告 "No files found for KieBase defaultKieBase"。 Drools 手册包含这句话 "These artifacts have to be added in the same position of a corresponding usual Maven project." 但没有简单地解释这意味着什么,这会更有帮助。)

当然,在您的 DRL 代码中没有 "global" 等同于编译知识库失败,即您的会话 运行 在空知识库上。

在另一个答案中阅读了您与@laune 的聊天后,我想问题现在已经确定:您的 KieBase 不包含您认为包含的工件(规则、全局变量等)。

不知道您的代码可能有什么问题,但我认为一个简单的解决方法可以使您摆脱现有的所有样板(和容易出错的)代码。

这里的想法是使用 KieHelper class 而不是 KieRepositoryKieFileSystemKieBuilder。实际上,创建 KieHelper class 是为了避免创建 KieBase 时涉及的复杂步骤(与 Drools 5.x 相比)。

使用 KieHelper class,您可以将代码重构为类似于以下内容:

KieHelper kieHelper = new KieHelper();
for (String ruleId : drls.keySet()) {
    kieHelper.addContent(drls.get(ruleId), ResourceType.DRL);
}
Results results = kieHelper.verify();
for (Message message : results.getMessages()) {
    log.error(">> Message ({}): {}", message.getLevel(), message.getText());
}

if (results.hasMessages(Message.Level.ERROR)) {
    throw new IllegalStateException("There are errors in the KB.");
}

KieSession ksession = kieHelper.build().newKieSession();

希望对您有所帮助,