What is the new accepted way of programmatically c

2019-03-19 05:25发布

问题:

In short I want to create, edit and delete rules from a rules repository at runtime. I'm having trouble figuring out how to do this in drools 6+.

I know in a previous version of drools (<= 5.6), that there was an XML representation of a .drl file and an API for working with it: https://docs.jboss.org/drools/release/5.6.0.Final/drools-expert-docs/html/ch04.html#d0e8052.

The drools documentation as of 5.6 indicates this deprecated and it appears to be completely removed at 6. I don't want to use an API that is already known to have no direct upgrade path.

Exposing the Guvnor or Workbench UIs to users for rules editing is also not a good fit here due to workflow requirements and due to the complexity of the web user interfaces. I want to create and manage the rules from Java code.

I want a better method than string templating to a .drl file for creating new rules and modifying rules. What exists for programmatically creating new rules from Java? I have done a lot of searching but can't seem to find a set of Java API calls for this.

回答1:

I don't know if this is the 'accepted' way, but with the following code I comine .drl files with programmatically created rules in Drools 6.

public KieContainer build(KieServices kieServices) {
    KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
    ReleaseId rid = kieServices.newReleaseId("com.example.rulesengine", 
        "model-test", "1.0-SNAPSHOT");
    kieFileSystem.generateAndWritePomXML(rid);

    kieFileSystem.write("src/main/resources/rules.drl", 
        getResource(kieServices, "rules.drl"));

    addRule(kieFileSystem);

    KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
    kieBuilder.buildAll();
    if (kieBuilder.getResults().hasMessages(Message.Level.ERROR)) {
        throw new RuntimeException("Build Errors:\n" + 
           kieBuilder.getResults().toString());
    }

    return kieServices.newKieContainer(rid);
}

private void addRule(KieFileSystem kieFileSystem) {
    PackageDescrBuilder packageDescrBuilder = DescrFactory.newPackage();
    packageDescrBuilder
            .name("com.example.model")
            .newRule()
            .name("Is of valid age")
            .lhs()
            .pattern("Person").constraint("age < 18").end()
            .pattern().id("$a", false).type("Action").end()
            .end()
            .rhs("$a.showBanner( false );")
            .end();

    String rules = new DrlDumper().dump(packageDescrBuilder.getDescr());
    kieFileSystem.write("src/main/resources/rule-1.drl", rules);
}

private Resource getResource(KieServices kieServices, String resourcePath) {
    try {
        InputStream is = Resources.getResource(resourcePath).openStream(); //guava
        return kieServices.getResources()
                  .newInputStreamResource(is)
                  .setResourceType(ResourceType.DRL);
    } catch (IOException e) {
        throw new RuntimeException("Failed to load drools resource file.", e);
    }
}

I use the Guava Resources class.



回答2:

There is no stable API for building rules from Java code. There is, of course, an API for the DRL compiler's parser, but it isn't stable and as complex as DRL rule syntax, which is considerable.

XML was an option where at least left hand side syntax was simple enough, which ended with 5.2 (IIRC). Now you can use Java's full expression syntax and more, combined with the many varied ways to compose CEs.

If your rules are exceptionally simple, you might come up with a model for rules that could be manipulated with a manageable API. Otherwise, your best bet is a text editor (or, of course, the Kie Workbench).



回答3:

The built-in way to programmatically create rules is based on a "Descr" fluent API, which manipulates the compiler's AST directly, bypassing the parser.

see the class org.drools.compiler.lang.api.DescrFactory

and the class org.drools.compiler.lang.DrlDumper to retrieve a DRL approximation from the AST.