流口水 API 混乱

Drools API confusion

我正在尝试评估 JBoss Drools 以用于我们从头开始构建的验证服务(通过 Spring Boot),但我在理解和区分多个 API 存在。

我的第一次尝试是一种相当简单的方法,或多或少直接从网络教程中获取,但它奏效了。使用 drools-core 6.0.1 的单一依赖项,我可以使用以下代码获得 RuleBase:

public static RuleBase readRule(String ruleFile) throws Exception {
    // read in the source
    Reader source = new InputStreamReader(RuleUtils.class.getClassLoader().getResourceAsStream("rules/" + ruleFile));

    PackageBuilder builder = new PackageBuilder();

    // this will parse and compile in one step
    builder.addPackageFromDrl(source);

    //check for errors
    if (builder.hasErrors()) {
        System.out.println(builder.getErrors().toString());
    }
    // get the compiled package (which is serializable)
    Package pkg = builder.getPackage();

    // add the package to a rulebase (deploy the rule package).
    RuleBase ruleBase = RuleBaseFactory.newRuleBase();
    ruleBase.addPackage(pkg);

    return ruleBase;
}

使用该 RuleBase,我可以创建一个新的有状态会话 (WorkingMemory),然后插入对象并触发我的规则。 然而,我已经读到 here 这种方法似乎已被弃用,而且我不想将过时版本的 Drools 用于一个闪亮的新项目(6.0.1 而不是当前版本 7.5.0)。

另一个在很多教程中很常见的 API 是:

public static RuleBase readRule(String ruleFile) throws Exception {
    // read in the source
    Reader source = new InputStreamReader(RuleUtils.class.getClassLoader().getResourceAsStream("rules/" + ruleFile));

    KnowledgeBuilder kBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();

    // this will parse and compile in one step
    kBuilder.add(ResourceFactory.newReaderResource(source), ResourceType.DRL);

    //check for errors
    if (kBuilder.hasErrors()) {
        System.out.println(kBuilder.getErrors().toString());
    }
    // get the compiled package (which is serializable)
    Collection<KnowledgePackage> pkgs = kBuilder.getKnowledgePackages();

    // add the package to a rulebase (deploy the rule package).
    KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
    kbase.addKnowledgePackages(pkgs);

    return kbase;
}

但这就是混乱开始的地方。所有这些 类 似乎都可以在两个单独的库(org.drools 和 org.kie.internal)中找到。使用 org.drools 我无法让上面的代码工作 - 我总是得到一个 java.lang.ClassNotFoundException: org.drools.builder.impl.KnowledgeBuilderFactoryServiceImpl - 我不知道我可能错过了哪个库。这是我的 pom.xml 的摘录,它已经比第一种方法大得多,尽管我不确定我实际需要哪些库(官方文档在这里不是很有帮助):

    <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-compiler</artifactId>
        <version>7.5.0.Final</version>
    </dependency>
    <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-core</artifactId>
        <version>7.5.0.Final</version>
    </dependency>
    <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-api</artifactId>
        <version>5.1.1</version>
    </dependency>
    <dependency>
        <groupId>org.kie</groupId>
        <artifactId>kie-api</artifactId>
        <version>7.5.0.Final</version>
    </dependency>
    <dependency>
        <groupId>org.kie</groupId>
        <artifactId>kie-internal</artifactId>
        <version>7.5.0.Final</version>
    </dependency>

当我使用其他实现时,我的知识库被标记为已弃用,这似乎是一个明显的提示,不再使用它。 然后我发现了另一个关于如何使用 Drools 实际实现它的建议 6.x 并尝试了它:

public static KieBase readRuleKie(String ruleFile) throws Exception {
    // read in the source
    Reader source = new InputStreamReader(RuleUtils.class.getClassLoader().getResourceAsStream("rules/" + ruleFile));

    // Get access to Drools services
    KieServices services = KieServices.Factory.get();

    // Obtain a new empty virtual file system
    KieFileSystem fileSystem = services.newKieFileSystem();

    // Load a DRL resource from src/main/resources into the virtual file system
    String location = "/rules/" + ruleFile;
    InputStream stream = RuleUtils.class.getClassLoader().getResourceAsStream("rules/" + ruleFile);
    Resource resource = ResourceFactory.newInputStreamResource(stream);
    fileSystem.write("src/main/resources" + location, resource);

    // Convert the files in the virtual file system into a builder
    KieBuilder builder = services.newKieBuilder(fileSystem).buildAll();

    // Check for errors, print them and stop if any
    Results results = builder.getResults();
    if (results.hasMessages(Message.Level.ERROR)) {
        System.out.println(results.getMessages());
    }

    // Create a new kie base out of a repository and a container
    KieRepository repository = services.getRepository();
    KieContainer container = services.newKieContainer(repository.getDefaultReleaseId());
    KieBase base = container.getKieBase();

    return base;
}

现在,这确实有效,但之前还向我的项目添加了对版本 1.4.10 中的 XStream 的依赖项。但是,我似乎仍在使用已弃用的库来构建我的 KnowledgeBase/KieBase/RuleBase。此外,API 似乎随着每次迭代变得越来越冗长。

问题是,我需要对上面的代码做些什么或进行哪些更改才能让它与 Drools 7 一起工作? API 似乎已经完全改变了,我宁愿不在我的 META-INF 中使用 kmodule.xml 文件,这似乎是 JBoss 最喜欢的方法。

我总是可以只使用第一个示例,但是对于较新的 Drools APIs 来说这不再可能了,我想避免依赖旧库。

这应该适用于 7.x 的任何 Drools 版本:

private KieSession kieSession;

public void build() throws Exception {
    KieServices kieServices = KieServices.Factory.get();
    KieFileSystem kfs = kieServices.newKieFileSystem();
    FileInputStream fis = new FileInputStream( "simple/simple.drl" );
    kfs.write( "src/main/resources/simple.drl",
               kieServices.getResources().newInputStreamResource( fis ) );
    KieBuilder kieBuilder = kieServices.newKieBuilder( kfs ).buildAll();
    Results results = kieBuilder.getResults();
    if( results.hasMessages( Message.Level.ERROR ) ){
        System.out.println( results.getMessages() );
        throw new IllegalStateException( "### errors ###" );
    }
    KieContainer kieContainer =
        kieServices.newKieContainer( kieServices.getRepository().getDefaultReleaseId() );
    KieBase kieBase = kieContainer.getKieBase();
    kieSession = kieBase.newKieSession();
}

考虑到您需要选择将多个资源加载到 kfs 中,需要一个可以响应错误的点,并且需要一个机会来序列化创建的 KieBase,这还不错。

至于库,请检查分发包中包含的内容并进行相应操作。对于 7.3.0 Final,基本的类路径设置如下(没有任何保证 - 仅作为指南):

root=/extra/drools-distribution-7.3.0.Final/binaries
tag=7.3.0.Final
export CLASSPATH=".:$root/drools-core-${tag}.jar:$root/kie-api-${tag}.jar:$root/kie-internal-${tag}.jar:$root/knowledge-internal-api-${tag}.jar:$root/drools-compiler-${tag}.jar:$root/antlr-runtime-3.5.2.jar:$root/ecj-4.4.2.jar:$root/mvel2-2.3.0.Final.jar:/extra/quartz-1.8.3/quartz-1.8.3.jar:$root/drools-decisiontables-${tag}.jar:$root/drools-templates-${tag}.jar:$root/protobuf-java-2.6.0.jar:$root/slf4j-api-1.7.7.jar:$root/xstream-1.4.9.jar:$SLF4J"