Исключение Захват в LHS Drools

У меня проблема, когда предложение when правила drools генерирует MethodNotFoundException. Я ищу способ выяснить, какое правило это во время выполнения, чтобы удалить его из списка правил для использования.

Пример правила

Rule "FooBar"
when
 $V1 : Foo (    )  AND
 $V2 : FooBar(    ) from $V1.getGoodMethod()  AND
 $V3 : FooBarBar( status == "FooBar" ) from $V2.getBadMethod()  
reply : FooFooBar()
then
reply.getList().add("FooBar");
end

Итак, getBadMethod на FooBar не существует. Я хотел бы узнать, что это такое, и удалить его из списка правил для использования.

Пробованные и неудачные решения:

Я попытался расширить DefaultAgendaEventListener и переопределить метод beforeActivationFired, чтобы добавить правило, запущенное в список. Я надеялся, что последний в списке будет тем, кто выбросил ошибку, но, к сожалению, это не получилось.

Теперь я попытался добавить правила "всегда истинные" перед всеми моими правилами. Они записывают имя правила, которое появляется после него. Проблема заключается в том, что в предложении WHEN отсутствует исключение, и ничего не регистрируется. Как будто никакие правила не срабатывают, когда возникает исключение, такое как выше.

Все проблемы связаны с динамическим кодом генерации слюни. Я хотел бы использовать два подхода к исправлению кода генерации и перехватывать исключения, подобные тем, которые перечислены в этом сообщении.

Примечание: Я проверяю ошибки в построителе. Я не получаю ошибок из приведенного ниже кода.

KnowledgeBuilderErrors errors = builder.getErrors();

if (!errors.isEmpty()) {
    for (KnowledgeBuilderError error : errors) {
        ...
    }
}

Ответы

Ответ 1

Как я понимаю, перед выполнением метода fireAllRules() ниже должны выполняться следующие шаги:

  • Добавить правила в конструктор пакетов/знаний
  • Подтвердите, что в Правилах нет ошибок.
  • Правила вложения в рабочую память

Конечно, можно стрелять в Rule без шага 2, но эта практика может привести к проблемам, упомянутым в этом вопросе. Если бы я был вами, я бы выполнил следующую логику, чтобы исправить вашу проблему:

Шаг 1:

private RuleBase initialiseDrools() throws IOException, DroolsParserException {
    PackageBuilder packageBuilder = readRules();
    return addRulesToWorkingMemory(packageBuilder);
}

Шаг 2:

private PackageBuilder readRules() throws DroolsParserException, IOException {
    PackageBuilder packageBuilder = new PackageBuilder();
    PackageBuilder intermPackageBuilder = null;

    listOfReader = dynamicRuleReader(); // Here goes your application code

    for(Reader reader : listOfReader){ 
        try{
            intermPackageBuilder = new PackageBuilder();
            intermPackageBuilder.addPackage(reader);
            assertNoRuleErrors(intermPackageBuilder); // This is the core step. 
            // Above line throws an exception, every time a rules fails. You can persist this exception for production debugging
            packageBuilder.addPackage(reader);
        }catch(DroolsParserException | IOException e){
            logger.error("Rules contain error, so skip adding them to the Package Builder");
        }
    }

    return packageBuilder;
}

Шаг 3:

public void shouldFireAllRules() throws IOException, DroolsParserException {
    RuleBase ruleBase = initialiseDrools();
    WorkingMemory workingMemory = ruleBase.newStatefulSession();
    int expectedNumberOfRulesFired = 2; // Idealy this number should be equal to the number of total rules injected in the Working memory

    int actualNumberOfRulesFired = workingMemory.fireAllRules();

    assertThat(actualNumberOfRulesFired, is(expectedNumberOfRulesFired));
}

Используя вышеописанный метод, вы не будете выполнять правило с ошибками, и описанная выше ситуация не возникнет. Тем не менее, я по-прежнему считаю, что вам следует больше сосредоточиться на части кода, генерирующей ошибочные правила, и описанном выше методе только для отслеживания и сохранения таких случаев.