Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stopping the chain if a Rule returns false #77

Closed
darrellme opened this issue Jun 29, 2017 · 13 comments
Closed

Stopping the chain if a Rule returns false #77

darrellme opened this issue Jun 29, 2017 · 13 comments

Comments

@darrellme
Copy link

Hi

If I want to add a bunch of rules, where I want the result to contain success ONLY if all rules are successful, is this possible currently. So, lets say that I have two rules, the first one checks if a user is Male, the second checks whether the users age is less than 40. If the user happens to be female, then the first rule will return false, but the second rule will still process. If the second rule returns true (the user is less than 40), then the rulebook result is true, even though I actually want it to be false. Essentially I'd like to be able to stop the chain should a rule fail, but this doesn't look possible. Is there another way of doing this possibly ?

Thanks

Darrell

@darrellme darrellme changed the title Stopping the chain should a Rule return false Stopping the chain if a Rule returns false Jun 29, 2017
@Clayton7510
Copy link
Collaborator

My apologies for the delayed response. I was on vacation for a bit.

I think what you are looking for was answered in this issue: #74

@darrellme
Copy link
Author

Hi

Unfortunately I'm not using the POJO rules and the @then annotation. I need to dynamically create the various rules so I'm using the RuleBuilder.create(..) method, which doesn't look like I can return a RuleState from the then method. Is there another way of doing it ?

Thanks

D

@Clayton7510
Copy link
Collaborator

Clayton7510 commented Jul 11, 2017

You can still do it! Pojo rules just use an adapter under the hood to convert to non-pojo rules. ;)

I'll post an example of how it looks with non-pojo rules sometime tomorrow - it would be today, but I am otherwise committed.

@Clayton7510
Copy link
Collaborator

Here is an example

RuleBook ruleBook = RuleBookBuilder.create()
            .addRule(rule -> rule.withNoSpecifiedFactType()
                .when(f->true)
                .then(f -> System.out.println("breaking the rule chain here"))
                .stop())
            .addRule(rule -> rule.withNoSpecifiedFactType()
                .when(f->true)
                .then(f -> System.out.println("next rule"))
                .stop()).build();

The first rule will execute and then it will break the rule chain after the rule is invoked. This shows how to break the rule chain when the rule evaluates to true. In order for a rule to perform any action, including breaking the rule chain, its 'when' condition must be true and its 'then' condition must be invoked. Of course, you could always have a rule that breaks the rule chain based on the inverse being evaluated in a 'when' statement and then having the stop() method set on that rule. A trivial example would be as follows.

RuleBook ruleBook = RuleBookBuilder.create()
            .addRule(rule -> rule.withNoSpecifiedFactType()
                .when(f-> !isTrue)
                .then(f -> {})
                .stop()) //stops the rule chain if isTrue == false
            .addRule(rule -> rule.withNoSpecifiedFactType()
                .when(f->true)
                .then(f -> System.out.println("next rule"))
                .stop()).build();

@Clayton7510
Copy link
Collaborator

closing due to inactivity

@darrellme
Copy link
Author

Sorry for the late reply. Many thanks for the example, although its not quite what I was hoping for as the result of the when needs to evaluate to true to execute the then, which is where the rule is used to break the rule chain. However, I'd like to be able to break the rule chain if the when fails and only perform the then if the when is successful. Kind of like the the .orElse terminology of java 8. Would this be possible ?

@Clayton7510 Clayton7510 reopened this Jul 20, 2017
@Clayton7510
Copy link
Collaborator

A related question was asked in Issue #79. In the interest of DRY, I will paraphrase the response :)

The decision not to allow for rules firing on 'else' was intentional. The idea being that each rule is an independent action that executes given some specific state. There was also a concern that building out if/then/else logic could lead to nesting rules and basically creating the exact kind of conditional branching chain complexity that rules are intended to address.

With that being said, adding in a feature that would allow for breaking the rule chain on a 'false' rule... that could happen. But it would be specific to the CoR implementation of RuleBook (currently, the only implementation). Future RuleBook implementations (future sate, there will be more than one packaged implementation), however, may have different execution sequences, where that would not be possible.

@darrellme
Copy link
Author

That would be great. I don't think it would be unreasonable to simply have a setting to determine whether a rule chain should break on failure of a rule, that would suit my purposes entirely (well, certainly for the foreseeable future). What I'm trying to avoid is having to have a negative rule for each positive rule with the negative rule simply breaking the chain...it seems a little excessive :-).

@Clayton7510 Clayton7510 added this to the Release 0.8 milestone Jul 27, 2017
@Clayton7510
Copy link
Collaborator

This update is on deck for the v0.8 release. v0.7 is planned for release to Maven Central on August 7. v0.8 is due to be released by the end of August and the SNAPSHOT release will be pushed on August 7. The v0.8 code is currently in the Issue67_EnhanceDSL branch which includes DSL related feature updates for v0.8.

@Clayton7510
Copy link
Collaborator

Here's what is planned:
Upon release, rules can break the rule chain for compatible RuleBooks as follows.

RuleBook ruleBook = RuleBookBuilder.create()
        .addRule(
            RuleBuilder.create(GoldenRule.class, true) //second param indicates that on failure this rule can stop the rule chain
                .withFactType(String.class)
                .when(facts -> false)
                .then(someConsumer)
                .stop() //signals that this rule stops the rule chain
                .build())
        .addRule(
            RuleBuilder.create() //this rule will never be invoked since the above rule stopped the rule chain when its condition was false
                .withFactType(String.class)
                .when(facts -> true)
                .then(someOtherConsumer)
                .build())
        .build();

Since this behavior is specific to sequential rules execution, it can only work with RuleBook implementations that use sequential rules execution (i.e. CoRRuleBook). So, the default behavior is still when a rule fails or its condition is not met, the rule chain continues. However, if a developer would like to make so that on a failure or failed rule condition, the rule breaks the rule chain, they may do so by specifying that in the creation of the rule (only available via RuleBuilder or the rule's constructor) using the optional boolean parameter. In that case, those rules that do not error and their condition is true will NOT break the rule chain; it will only break if the rule's condition evaluates false or the rule fails.

@Clayton7510 Clayton7510 self-assigned this Aug 3, 2017
@Clayton7510
Copy link
Collaborator

This is updated in the 0.8-SNAPSHOT. One change was made, however. The above code would now look like this:

RuleBook ruleBook = RuleBookBuilder.create()
        .addRule(
            RuleBuilder.create(GoldenRule.class, STOP_ON_FAILURE) //second param indicates that on failure this rule can stop the rule chain
                .withFactType(String.class)
                .when(facts -> false)
                .then(someConsumer)
                .stop() //signals that this rule stops the rule chain
                .build())
        .addRule(
            RuleBuilder.create() //this rule will never be invoked since the above rule stopped the rule chain when its condition was false
                .withFactType(String.class)
                .when(facts -> true)
                .then(someOtherConsumer)
                .build())
        .build();

@Clayton7510
Copy link
Collaborator

This enhancement was released in v0.8.

@darrellme
Copy link
Author

Cool, thanks, I'll take at this hopefully sometime this week, many thanks for that

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants