如何在没有任何插件的情况下使用grails3中的drools?

时间:2016-11-07 13:43:46

标签: plugins drools grails3

是否可以在没有任何插件安装的情况下在GRAILS3中使用drools规则引擎?我问这个是因为我知道drools是用java实现的,而{Smprell为actual official plugin实现了GRAILS(显然)不再有效。

1 个答案:

答案 0 :(得分:1)

经过大量调查和多次尝试后,我获得了一个小型GRAILS3 API服务,通过它可以使用DROOLS引擎处理数据而无需任何插件。所有这一切都是可能的,因为DROOLS基于Java并且因为GRAILS和Java之间的完美兼容性。
您所需要的只是以下内容:

  1. 在build.gradle中包含最小的DROOLS依赖项
  2. 选择一个文件夹来存储files.drl
  3. 有一些实体用作事实来处理(不强制要求它们,所以我跳过hibernate配置)
  4. 实施服务以构建规则库知识并获得会话
  5. 将一些方法实现到API控制器中以通过DROOLS处理数据(从服务获得其会话)
  6. 下面是一个简单的例子:

    DROOLS依赖项(在build.gradle中):

    runtime "org.drools:drools-compiler:6.5.0.Final"
    compile "org.drools:drools-core:6.5.0.Final"
    compile "org.drools:knowledge-api:6.5.0.Final"
    

    src / rules中的DRL存储(对此路径的引用将在服务中,见下文):myrules.drl

    import my.entities.Book;
    import java.util.List;
    
    rule "Find author"
       salience 10
       when
        $book: Book( author=="Shakespeare" )
       then
        System.out.println("Book found, date:"+$book.getDate0());
    end
    

    某个实体,例如Book:

    package my.entities
    import java.util.Date
    
    class Book {
        String title, author
        Date date0
    }
    

    建立DROOLS知识并获得会话的服务(我准备了一个无状态引擎,比有状态引擎更轻):

    package my.services
    import grails.converters.*
    
    import org.kie.api.runtime.*;
    import org.kie.internal.io.ResourceFactory;
    import org.kie.api.*;
    import org.kie.api.io.*;
    import org.kie.api.builder.*;
    
    class DroolsService  {
    
    def getSession() {
            def path    = "src/rules"
            def lru = ["myrules.drl"]
            def rules   = []
            lru.each{
                rules.add("${path}${it}")
            }
            StatelessKieSession ksess   = buildSession(rules)
            return ksess
        }
    }
    
    private buildSession(def lfile) {
        println "Building DROOLS session..."
        try {
            def lres    = []
            lfile.each{
                Resource resource   = ResourceFactory.newFileResource(new File(it));
                lres.add(resource)
            }
    
            KieContainer kieContainer = buildKieContainer(lres)
            StatelessKieSession kieSession = kieContainer.newStatelessKieSession()
            return kieSession
        } catch(Exception e) {
            e.printStackTrace()
            return null
        }
    
    protected KieContainer buildKieContainer(def lres) {
        KieServices kieServices = KieServices.Factory.get()
        KieFileSystem kieFileSystem = kieServices.newKieFileSystem()
        lres.each{
            kieFileSystem.write("src/main/resources/rule.drl", it)  
        }
    
        KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem).buildAll()
        Results results = kieBuilder.results
        if (results.hasMessages(Message.Level.ERROR)) {
            throw new IllegalStateException(this.class.name + ": " + results.messages.toString())
        }
        KieContainer kieContainer = kieServices.newKieContainer(kieServices.repository.defaultReleaseId)
        kieContainer
    }
    
    }
    

    在API控制器中使用服务:

    class ApiController  {
    
    def droolsService
    
    def proc = {
        def sess    = droolsService.getSession()
    
        def mess    = "ok DROOLS proc from JSON"
        Book book   = null
    
        if (params.contbook) {
            book = new Book(JSON.parse(params.contbook))
            sess.execute book
        } 
    
        response.status  = 200 
        render mess
    }
    

    在控制器中,我从参数中获取json数据并通过它们填充实体,以便使用DROOLS服务初始化的规则引擎执行它。当然这是一个非常简单的解决方案,但它正在发挥作用。

    一些注意事项:

    • 每个drl规则的RHS部分("然后")必须是java,因此,如示例中所示,您不能直接访问实体的私有属性,但必须使用getter或setter (由GRAILS隐式创建)
    • getSession创建知识的新构建和新会话并且不是最优的,您可以重新设计它以存储DROOLS会话,然后通过用户会话重复使用
    • 您可以在同一文件夹中包含多个files.drl,然后您必须在服务中列出所有这些文件才能将它们打包到知识引擎中

    希望所有这些都有用。