Search code examples
jbossdrools

Why does this rule run more than once?


I have created this rule:

rule "Product PRODUCT_A is not available from other insurers as INSURER_A"
when
    $p : Policy(insurer.name != "INSURER_A", product.name == "PRODUCT_A", $v : validations)
    not (Validation(level == ValidationLevel.ERROR) from $v)
then
    log.info("Matching rule for {} with validations: {}", $p.getInsurer().getName(), $p.getValidations());
    $p.addValidation(new Validation(ValidationLevel.ERROR, "This insurance is not available for " + $p.getInsurer().getName()));
end

When I inject 4 Policy objects, all for PRODUCT_A and one with an insurer name of INSURER_A and the other three with other names, the logging shows me:

DroolsController - Matching rule for INSURER_B with validations: []
DroolsController - Matching rule for INSURER_C with validations: [Validation(id=0, level=ERROR, description=This insurance is not available for INSURER_B)]
DroolsController - Matching rule for INSURER_D with validations: [Validation(id=0, level=ERROR, description=This insurance is not available for INSURER_B), Validation(id=0, level=ERROR, description=This insurance is not available for INSURER_C)]
DroolsController - Matching rule for INSURER_B with validations: [Validation(id=0, level=ERROR, description=This insurance is not available for INSURER_D), Validation(id=0, level=ERROR, description=This insurance is not available for INSURER_B), Validation(id=0, level=ERROR, description=This insurance is not available for INSURER_C)]
DroolsController - Matching rule for INSURER_C with validations: [Validation(id=0, level=ERROR, description=This insurance is not available for INSURER_D), Validation(id=0, level=ERROR, description=This insurance is not available for INSURER_B), Validation(id=0, level=ERROR, description=This insurance is not available for INSURER_C)]
DroolsController - Matching rule for INSURER_D with validations: [Validation(id=0, level=ERROR, description=This insurance is not available for INSURER_D), Validation(id=0, level=ERROR, description=This insurance is not available for INSURER_B), Validation(id=0, level=ERROR, description=This insurance is not available for INSURER_C)]

This looks very strange to me. I was expecting that on every Policy (except for INSURER_A) there would be one Validation object. However, the validation objects seems to be added to all the Policy objects. When I read the results the every validation object is added to all policies, even on the PRODUCT_A policy.

What is wrong with my rule? How can I change the rule so it behaves as expected?


Solution

  • This has nothing to do with the defined rules.

    The policy facts you are entering are cloned objects. However, this was a shallow clone instead of a deep clone. So the validations list in the policy objects still pointed to the same validations list in the clone.

    When adding a validation to one object, because the other objects referenced the same list, they would also be added to the other objects.

    Drools first creates an agenda with all conditions that are true. When you modify an object, it finds that it is changed and will update the agenda accordingly. However, the policy object did not change, so the rule is run even when there are new validations in the referenced list.