从 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)
- DRL 作为字符串列表从数据库中检索。
- 我们不使用 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 而不是 KieRepository
、KieFileSystem
和 KieBuilder
。实际上,创建 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();
希望对您有所帮助,
java.lang.RuntimeException: Unexpected global [log]
at org.drools.core.impl.StatefulKnowledgeSessionImpl.setGlobal(StatefulKnowledgeSessionImpl.java:1163)
- DRL 作为字符串列表从数据库中检索。
- 我们不使用 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 而不是 KieRepository
、KieFileSystem
和 KieBuilder
。实际上,创建 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();
希望对您有所帮助,