Skip to content

feat: add rule engine design pattern#3548

Open
MohamedMBG wants to merge 1 commit into
iluwatar:masterfrom
MohamedMBG:issue-1219-rule-engine
Open

feat: add rule engine design pattern#3548
MohamedMBG wants to merge 1 commit into
iluwatar:masterfrom
MohamedMBG:issue-1219-rule-engine

Conversation

@MohamedMBG

Copy link
Copy Markdown

Closes #1219

Adds a new rule-engine module implementing the Rule Engine design pattern.

  • Rule<T> abstraction separating evaluate (decision) from execute (action)
  • Three concrete rules: minimum age, minimum income, credit score
  • RuleEngine<T> evaluates all rules in insertion order (no short-circuit) against a LoanApplication context
  • Immutable RuleEngineResult reporting approved flag plus passed/failed rule names
  • Defensive copies / immutability throughout; null contexts and null rules rejected
  • Unit tests (19) covering pass/fail per rule, engine composition, ordering, empty engine, null inputs, and defensive copying
  • Module README documenting intent, behavioral decisions, trade-offs, and a PlantUML class diagram

Registered in the root pom.xml modules list.

Add an educational rule-engine module demonstrating the Rule Engine
pattern. Each business rule is an independent object exposing evaluate
(decision) and execute (action); a RuleEngine evaluates a collection of
rules against an immutable loan-application context in insertion order,
runs the passing rules, and reports every passed and failed rule via an
immutable RuleEngineResult. Includes three concrete rules, an App demo,
unit tests, README, and class diagram.
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

PR Summary

Closes #1219. Added a new rule-engine module implementing the Rule Engine design pattern.

  • Rule<T> abstraction separating evaluate (decision) from execute (action)
  • Three concrete rules: MinimumAgeRule, MinimumIncomeRule, CreditScoreRule
  • RuleEngine<T> evaluates all rules in insertion order (no short-circuit) against a LoanApplication context
  • Immutable RuleEngineResult reporting approved flag plus passed/failed rule names
  • Defensive copies / immutability throughout; null contexts and null rules rejected
  • Unit tests (19) covering pass/fail per rule, engine composition, ordering, empty engine, null inputs, and defensive copying
  • Module README documenting intent, behavioral decisions, trade-offs, and a PlantUML class diagram
  • Registered in the root pom.xml modules list.

Changes

File Summary
pom.xml Updated root Maven pom.xml to include the new rule-engine module, registering it in the multi-module build.
rule-engine/README.md Documentation for the Rule Engine pattern, describing intent, usage, semantics and examples.
rule-engine/etc/rule-engine.urm.puml PlantUML class diagram for the Rule Engine pattern showing interfaces and relationships.
rule-engine/pom.xml Module POM for rule-engine with dependencies (SLF4J, Logback, JUnit) and build configuration.
rule-engine/src/main/java/com/iluwatar/ruleengine/App.java Demo app that builds a RuleEngine<LoanApplication> with three rules and runs two sample applications, printing results.
rule-engine/src/main/java/com/iluwatar/ruleengine/CreditScoreRule.java Concrete Rule<LoanApplication> implementing minimum credit score check; provides name, evaluate, and execute methods.
rule-engine/src/main/java/com/iluwatar/ruleengine/LoanApplication.java Immutable LoanApplication context (record) used by all rules.
rule-engine/src/main/java/com/iluwatar/ruleengine/MinimumAgeRule.java Concrete Rule<LoanApplication> enforcing minimum age; implements evaluate and execute with logging.
rule-engine/src/main/java/com/iluwatar/ruleengine/MinimumIncomeRule.java Concrete Rule<LoanApplication> enforcing minimum income; implements evaluate and execute.
rule-engine/src/main/java/com/iluwatar/ruleengine/Rule.java Abstract Rule<T> interface defining name, evaluate, and execute to separate decision from action.
rule-engine/src/main/java/com/iluwatar/ruleengine/RuleEngine.java Engine that coordinates rules, evaluates all in order, and returns RuleEngineResult; supports defensive copies and exposes rules.
rule-engine/src/main/java/com/iluwatar/ruleengine/RuleEngineResult.java Immutable RuleEngineResult capturing approval status and lists of passed/failed rules with defensive copies.
rule-engine/src/test/java/com/iluwatar/ruleengine/AppTest.java Test ensuring App.main runs without throwing exceptions.
rule-engine/src/test/java/com/iluwatar/ruleengine/LoanRulesTest.java Unit tests for individual rules across thresholds (pass/fail) and that execute runs when applicable.
rule-engine/src/test/java/com/iluwatar/ruleengine/RuleEngineResultTest.java Tests for defensive copying and immutability of RuleEngineResult lists.
rule-engine/src/test/java/com/iluwatar/ruleengine/RuleEngineTest.java Integration tests covering approvals, rejections, ordering, empty engine, and null input handling.

autogenerated by presubmit.ai

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 Pull request needs attention.

Review Summary

Commits Considered (1)
  • 1e959a1: feat: add rule engine design pattern

Add an educational rule-engine module demonstrating the Rule Engine
pattern. Each business rule is an independent object exposing evaluate
(decision) and execute (action); a RuleEngine evaluates a collection of
rules against an immutable loan-application context in insertion order,
runs the passing rules, and reports every passed and failed rule via an
immutable RuleEngineResult. Includes three concrete rules, an App demo,
unit tests, README, and class diagram.

Files Processed (16)
  • pom.xml (1 hunk)
  • rule-engine/README.md (1 hunk)
  • rule-engine/etc/rule-engine.urm.puml (1 hunk)
  • rule-engine/pom.xml (1 hunk)
  • rule-engine/src/main/java/com/iluwatar/ruleengine/App.java (1 hunk)
  • rule-engine/src/main/java/com/iluwatar/ruleengine/CreditScoreRule.java (1 hunk)
  • rule-engine/src/main/java/com/iluwatar/ruleengine/LoanApplication.java (1 hunk)
  • rule-engine/src/main/java/com/iluwatar/ruleengine/MinimumAgeRule.java (1 hunk)
  • rule-engine/src/main/java/com/iluwatar/ruleengine/MinimumIncomeRule.java (1 hunk)
  • rule-engine/src/main/java/com/iluwatar/ruleengine/Rule.java (1 hunk)
  • rule-engine/src/main/java/com/iluwatar/ruleengine/RuleEngine.java (1 hunk)
  • rule-engine/src/main/java/com/iluwatar/ruleengine/RuleEngineResult.java (1 hunk)
  • rule-engine/src/test/java/com/iluwatar/ruleengine/AppTest.java (1 hunk)
  • rule-engine/src/test/java/com/iluwatar/ruleengine/LoanRulesTest.java (1 hunk)
  • rule-engine/src/test/java/com/iluwatar/ruleengine/RuleEngineResultTest.java (1 hunk)
  • rule-engine/src/test/java/com/iluwatar/ruleengine/RuleEngineTest.java (1 hunk)
Actionable Comments (4)
  • rule-engine/src/main/java/com/iluwatar/ruleengine/App.java [64-64]

    best_practice: "Logger name mismatch with Lombok"

  • rule-engine/src/main/java/com/iluwatar/ruleengine/MinimumAgeRule.java [56-56]

    best_practice: "Logger name mismatch in MinimumAgeRule.execute"

  • rule-engine/src/main/java/com/iluwatar/ruleengine/MinimumIncomeRule.java [56-60]

    best_practice: "Logger name mismatch in MinimumIncomeRule.execute"

  • rule-engine/src/main/java/com/iluwatar/ruleengine/CreditScoreRule.java [56-60]

    best_practice: "Logger name mismatch in CreditScoreRule.execute"

Skipped Comments (0)


private static void report(RuleEngineResult result) {
if (result.approved()) {
LOGGER.info("Loan approved. Passed rules: {}", result.passedRules());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logger name mismatch with Lombok's @slf4j annotation. Lombok typically exposes a 'log' field when using @slf4j; update to use log.info(...) (or switch to a logger annotation that matches LOGGER).


@Override
public void execute(LoanApplication context) {
LOGGER.info("Applicant age {} meets the minimum age of {}.", context.age(), minimumAge);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logger name mismatch in execute() for MinimumAgeRule. Replace LOGGER with log to align with @slf4j usage.

Comment on lines +56 to +60
LOGGER.info(
"Applicant income {} meets the minimum income of {}.",
context.monthlyIncome(),
minimumIncome);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logger name mismatch across the multi-line execute() in MinimumIncomeRule. Replace LOGGER with log and maintain formatting.

Comment on lines +56 to +60
LOGGER.info(
"Applicant credit score {} meets the minimum score of {}.",
context.creditScore(),
minimumScore);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logger name mismatch across the multi-line execute() in CreditScoreRule. Replace LOGGER with log to align with Lombok @slf4j usage.

@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.33333% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 83.27%. Comparing base (74d2dbe) to head (1e959a1).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...ine/src/main/java/com/iluwatar/ruleengine/App.java 92.30% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #3548      +/-   ##
============================================
+ Coverage     83.24%   83.27%   +0.02%     
- Complexity     4025     4056      +31     
============================================
  Files          1060     1067       +7     
  Lines         14246    14306      +60     
  Branches        686      688       +2     
============================================
+ Hits          11859    11913      +54     
- Misses         2100     2108       +8     
+ Partials        287      285       -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@HattoriHenzo HattoriHenzo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a globale review, I would suggest you to organize your project into different package or module with the RuleEngine (Abstraction) and the rule implementation (Implementations).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rule engine design pattern

2 participants