Можно ли использовать механизм правил drools в GRAILS3 без установки плагина? Я спрашиваю об этом, потому что знаю, что drools реализован на Java, а настоящим официальным плагином Кена Сипрелла для GRAILS является ( видимо) больше не работает.
Как использовать drools в Grails3 без каких-либо плагинов?
Ответы (1)
После долгих исследований и многих попыток я получил небольшой API-сервис GRAILS3, с помощью которого можно обрабатывать данные с помощью движка DROOLS без каких-либо плагинов. Все это возможно благодаря тому, что DROOLS основан на Java и благодаря идеальной совместимости между GRAILS и Java.
Все, что вам нужно, это следующее:
- включить минимальную зависимость DROOLS в build.gradle
- выберите папку для хранения files.drl
- есть некоторые объекты для использования в качестве фактов для обработки (не обязательно сохранять их, поэтому я пропускаю настройку гибернации)
- внедрить сервис для создания базы знаний правил и получения сеанса
- внедрить некоторые методы в контроллер API для обработки данных через DROOLS (получив сеанс от службы)
Ниже приведен простой пример всего этого:
Зависимости 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"
Хранилище DRL в src/rules (ссылка на этот путь будет в сервисе, см. ниже): 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
Некоторая сущность, например Книга:
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. Конечно, это очень простое решение, но оно работает.
Некоторые примечания:
- часть RHS каждого правила drl (после "then") должна быть java, поэтому, как в примере, вы не можете получить прямой доступ к частному свойству объекта, но вы должны использовать геттер или сеттер (неявно созданный GRAILS)
- getSession создает новую сборку знаний и новый сеанс, и это не оптимально, вы можете изменить его, чтобы сохранить сеанс DROOLS, а затем повторно использовать его через сеанс пользователя.
- у вас может быть несколько файлов .drl в одной папке и тогда вы должны перечислить их все в сервисе, чтобы запаковать их в движок знаний
Надеюсь, что все это полезно.