Drools 规则 - 多个问题(停止执行、停止执行的条件)不起作用

Drools rules - multiple issues (halt execution, condition to stop execution) not working

我正在使用 Drools 6.1。0.FINAL 和一个无状态会话来触发所有规则。

我的 .drl 文件中有以下 2 个简单规则。

rule "Null Check"
    when
        $paymentHolder : PaymentHolder(pmtRequest.requestDetails == null 
        || pmtRequest.requestDetails.paymentData == null
        || pmtRequest.requestDetails.paymentData.accountDetails == null
        || pmtRequest.requestDetails.paymentData.payments == null
        || pmtRequest.requestDetails.paymentData.payments.payment == null
        || pmtRequest.requestDetails.paymentData.payments.payment.get(0).tenderDetails == null
        || pmtRequest.requestDetails.paymentData.payments.payment.get(0).tenderDetails.paymentCardDetails == null
        || pmtRequest.requestDetails.paymentData.payments.payment.get(0).tenderDetails.paymentCardDetails.authorizationInfo == null)
    then
        System.out.println("Some Manadatory data is null ");
        // populate error code and error message
        List<ErrorHolder> errors = $paymentHolder.getErrors();
        ErrorHolder erroHolder = new ErrorHolder();
        errors.add(erroHolder);
      erroHolder.setErrorCode(com.wdpr.payment.exception.ErrorCode.MANDATORY_DATA_MISSING);
        // drools.halt();
       // kcontext.getKieRuntime().halt();        
end

rule "Amount is -ve"
    when
        
        $paymentHolder : PaymentHolder(errors.size() == 0)
    $paymentHolder(pmtRequest.getRequestDetails()!.getPaymentData().getPayments().getPayment().get(0).getAmount().getAmount() < 0)
    then
        //System.out.println(paymentHolder.getProcessId());
        System.out.println("Amount is -ve");
        //throw new com.wdpr.payment.exception.PaymentPlatformException(com.wdpr.payment.exception.ErrorCode.DATA_RANGE_INVALID, "Data Range Invalid - Amount", null);
end

我想这样做:如果第一个规则为真,则不执行任何其他规则并退出 .drl 文件。

我试过以下方法:

  1. 试图在其中抛出一个运行时异常,然后在第一条规则中阻止,但它仍然会进入第二条规则,因为 NullPointerException 而失败。

  2. 添加了 drools.halt() 和 kcontext.getKieRuntime().halt() 但没有用,仍将进入下一个规则。

  3. 所以我在第一条规则的自定义 erroHolder 中添加了一些错误代码,并在第二条规则中检查了相同的条件,这样它就不会被执行,但它仍然会被执行并抛出 NullPointerException。

如果我删除第二条规则,那么第一条规则会完美执行并打印系统输出。但是当我 运行 我的 .drl 使用这两条规则时,它让我低于 NPE

堆栈跟踪

Exception in thread "main" java.lang.RuntimeException: Error while creating KieBase[Message [id=1, level=ERROR, path=com/my/payment/rules/validation.drl, line=40, column=0
   text=[ERR 102] Line 40:53 mismatched input '!.' in rule "Amount is -ve"], Message [id=2, level=ERROR, path=com/my/payment/rules/validation.drl, line=0, column=0
   text=Parser returned a null Package]]
    at org.drools.compiler.kie.builder.impl.KieContainerImpl.getKieBase(KieContainerImpl.java:349)
    at org.drools.compiler.kie.builder.impl.KieContainerImpl.newStatelessKieSession(KieContainerImpl.java:540)
    at org.drools.compiler.kie.builder.impl.KieContainerImpl.newStatelessKieSession(KieContainerImpl.java:528)
    at com.my.payment.workflow.DroolsRuleProcessor.runRules(DroolsRuleProcessor.java:58)
    at com.my.payment.workflow.DroolsRuleProcessor.main(DroolsRuleProcessor.java:81)

我的 java 代码片段

// some code

final StatelessKieSession kSession = this.kContainer.newStatelessKieSession(rulesSession);

         // provide the necessary data and execute rules.
         kSession.execute(paymentHolder);

注意:我不想使用salient和activate-group

解决方法很简单(虽然你可能不喜欢)。为避免在评估访问包含对象的字段的约束时出现 NPE,请确保该字段不为 null 或将针对 null 的测试与访问相结合。

// (#1) either:
class PmtRequest {
    // guarantee non-null requestDetails
    List<rRequestDetail> requestDetails = new ArrayList<>(); 


// (#2) or:
when
$paymentHolder: PaymentHolder(errors.size() == 0,
                pmtRequest != null &&
                pmtRequest.getRequestDetails() ... )
then ...

对于深度嵌套的约束,这越来越不方便,这就是为什么建议不要编写此类访问,而是将包含的对象作为事实插入或在顶级对象中添加方法以访问包含的对象。

还有另一种选择 (#3):在规则执行中使用两个会话。新的 PaymentHolder 事实必须通过仅包含 nun-null 测试的第一个会话,然后才能将其插入第二个会话。

恕我直言,可靠的方法包括#1 和#3 的组合。

(问题的根本在于,在设计规则和应用程序之前,您需要考虑规则评估的工作方式。所有 约束在事实为已插入。来自 Drools 手册:条件评估与特定的评估序列或时间点无关,而是在生命周期中的任何时间不断发生引擎时间。)