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

Add rules engine listener #121

Closed
cemo opened this issue Nov 27, 2017 · 12 comments
Closed

Add rules engine listener #121

cemo opened this issue Nov 27, 2017 · 12 comments
Labels
Milestone

Comments

@cemo
Copy link

cemo commented Nov 27, 2017

I would like to fetch some data from database and pass into per rule. I noticed that there is RuleListener but it seems it is triggered per rule. I think that an API for per execution.

@fmbenhassine
Copy link
Member

Hi,

Yes the rule listener is executed per rule.

What do you mean an API per execution? Could you please give an example?

Kr
Mahmoud

@cemo
Copy link
Author

cemo commented Nov 28, 2017

I am in the process of implementing coupon campaigns. I would like to query database coupons before evaluations starting. I will pass them to rules as a fact. Specifically I need some hooks in com.clovify.mm.core.jeasy.LifeCycleAwareRulesEngine#apply before LOGGER.info("Rules evaluation started");.

BTW I had implemented a custom RulesEngine but It might be something wrong. I wanted to discuss as well. What is the best place to fetch some data for rules?

@fmbenhassine
Copy link
Member

Thank you for the example, I see now. Basically you are looking for something like a RulesEngineListener which is executed per rule set, not per rule. I'm thinking of:

public interface RulesEngineListener {
    void beforeFiringRules(Rules rules, Facts facts);
    void afterFiringRules(Rules rules, Facts facts);
}

With this listener, you can add custom behaviour before/after firing the whole rule set.

Is this correct? I want to make sure I correctly understand your request.

What is the best place to fetch some data for rules?

The best place would be in the RulesEngineListener#beforeFiringRules method 😄

@cemo
Copy link
Author

cemo commented Nov 28, 2017

Yeah exactly :) By the way I had added almost same class :)

public interface LifeCycleListener {
  void beforeEvaluates(Rules rules, Facts facts);
  void afterEvaluates(Rules rules, Facts facts);
}

But RulesEngineListener reflects better need. :)

@fmbenhassine
Copy link
Member

fmbenhassine commented Nov 28, 2017

ok cool. But in hindsight, do we really need such a listener? What would be the added value compared to something like:

Data data = .. // fetch data before rule set execution
facts.put("data", data);

rulesEngine.fire(rules, facts);

// check facts after rule set execution

The RuleListener makes sense since we don't have access to facts before/after the execution of each rule (unless there is only one registered rule of course). But in the case of RulesEngineListener, we have access to the facts before/after the whole execution. Why would I need to implement an listener, register it and make the engine call it for me instead of writing the code before/after calling the engine as in the example. Do you see the point?

@cemo
Copy link
Author

cemo commented Nov 28, 2017

I will have some modules which will encapsulated all logic. Such an interface will be a contract between modules and core logic.

@fmbenhassine
Copy link
Member

That makes perfect sense. The interface actually has some benefits:

  • may serve as contract between different modules (as you said)
  • may encapsulate some logic that can be reused
  • is more elegant than putting logic before/after running the engine (as in my previous comment)
  • is consistent with the existing API: having a RuleListener per rule and a RulesEngineListener per rule set makes sense

So let me plan this for next release!
I'll let you know when a snapshot version with the addition is published to give it a try before the release.

Thank you for this suggestion!

Kr,
Mahmoud

@fmbenhassine fmbenhassine added this to the v3.1 milestone Dec 6, 2017
@fmbenhassine fmbenhassine changed the title Per Execution Listener Add rules engine listener Dec 11, 2017
@cemo
Copy link
Author

cemo commented Dec 11, 2017

@benas

This commit is nice. The code reside in

public void fire(Rules rules, Facts facts) {
if (rules.isEmpty()) {
LOGGER.warn("No rules registered! Nothing to apply");
return;
}
logEngineParameters();
log(rules);
log(facts);
apply(rules, facts);
can be refactored into a listener. Instead of apply method, you can just use fire method. This will be nice since we can delegate in this case to default implementation.

@fmbenhassine
Copy link
Member

yes that was coming 😄 I was planning to add a DefaultRulesEngineListener (like the current DefaultRuleListener) to encapsulate the logging. This will remove the need for the apply method.

I will deploy v3.1 snapshot and keep you posted.
Thanks for the review!

@fmbenhassine
Copy link
Member

fmbenhassine commented Dec 11, 2017

This issue should be fixed now: methods were renamed to be able to use them in both fire and check methods. A default rules engine listener was added to encapsulate the logging logic.

Version 3.1.0-SNAPSHOT is deployed to maven central, @cemo can you give a try to the listener you requested?

@cemo
Copy link
Author

cemo commented Dec 12, 2017

tested. :shipit:

@cemo cemo closed this as completed Dec 12, 2017
@fmbenhassine
Copy link
Member

Great! thank you for your time!

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

No branches or pull requests

2 participants