Hello Dev.to community! š Iām thrilled to introduce LWRE (Lightweight Java Rule Engine), an open-source Java-based rule engine designed to tackle complex business logic with simplicity, performance, and scalability. If youāre building systems that require dynamic rule executionāthink validation pipelines, decision trees, or workflow automationāLWRE is here to make your life easier. Check it out at HamdiGhassen/lwre (Apache 2.0 licensed), and if you find it valuable, please give it a ā to help spread the word! š.
What is LWRE?
LWRE is a Java rule engine that lets you define, compile, and execute business rules using a powerful Domain-Specific Language (DSL). Itās built for developers who need flexibility without sacrificing performance or reliability. Whether youāre managing microservices, validating user inputs, or orchestrating workflows, LWRE provides a robust framework with features like dependency management, parallel execution, and fault tolerance.
Key Features
- Expressive DSL: Define rules with a clean syntax, supporting imports, variables, retries, timeouts, and control flow.
- Dynamic Compilation: Uses Janino to compile rules into Java classes at runtime, with caching for efficiency.
- Dependency Management: Organizes rules into directed acyclic graphs (DAGs) for optimized execution order, with cycle detection.
- Parallel Execution: Executes rule groups asynchronously using a thread pool, with configurable timeouts.
- Fault Tolerance: Supports retry policies with delays and conditions, plus a circuit breaker to prevent system overload.
-
Thread Safety: Built with
ConcurrentHashMap
, thread-local pools, and synchronized methods for concurrent environments. - Metrics & Tracing: Tracks execution metrics and supports debugging with optional tracing.
- Rule Versioning: Enables safe updates and rollbacks for experimentation.
-
Security: Restricts access to dangerous classes (e.g.,
java.lang.Runtime
) and enforces timeouts to prevent infinite loops.
Why Choose LWRE?
LWRE is lightweight and focused on simplicity, making it ideal for projects where you need dynamic rules without complex setup. Its DSL is intuitive, and its performance optimizationsālike cached compilation and precomputed execution pathsāensure it scales well in production.
Getting Started
Prerequisites
- Java 17 or higher
- Maven for dependency management
Installation
Add the Janino dependency to your pom.xml
:
<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>janino</artifactId>
<version>3.1.12</version>
</dependency>
Clone and build LWRE:
git clone https://github.com/HamdiGhassen/lwre.git
cd lwre
mvn clean install
In-Depth Example: User Validation Workflow
Letās walk through a practical example of using LWRE to validate a user and compute a credit score, with dependencies and retries. Below is a DSL defining two rules in a workflow:
#GLOBAL
userId : String
creditThreshold : Integer
#HELPER
int computeCreditScore(int base) {
return base * 2 + 50;
}
#RULE CheckUser
#GROUP UserWorkflow
#PRIORITY 1
#TIMEOUT 500 ms
#USE
userId : String as user FROM Global
creditThreshold : Integer as threshold FROM Global
#PRODUCE
isValid : Boolean
#CONDITION
return user != null && user.length() > 0;
#ACTION
isValid = true;
#FINAL
return isValid ? "User " + user + " is valid" : "Invalid user";
#RULE ComputeScore
#GROUP UserWorkflow
#PRIORITY 2
#NEXT_ON_SUCCESS Finalize
#USE
userId : String as user FROM Global
creditThreshold : Integer as threshold FROM Global
isValid : Boolean as isValid FROM RULE CheckUser
#PRODUCE
score : Integer
#CONDITION
return isValid && threshold >= 100;
#ACTION
score = computeCreditScore(threshold);
System.out.println("Computed score for " + user + ": " + score);
#FINAL
return score;
Explanation
-
CheckUser Rule: Validates the
userId
and setsisValid
. -
ComputeScore Rule: Depends on
CheckUser
(viaisValid
) and computes a credit score if the user is valid. It triggers aFinalize
rule (not shown) on success. -
Dependency Management: LWREās
RuleGraphProcessor
ensuresCheckUser
runs beforeComputeScore
by building a DAG. -
Global & Helper: Shared variables (
userId
,creditThreshold
) and a reusablecomputeCreditScore
method are defined globally.
Running the Workflow
Hereās how to execute this in Java:
import org.pulse.lwre.core.LWREngine;
public class Main {
public static void main(String[] args) throws Exception {
// Load DSL from file or string (dslContent)
LWREngine engine = new LWREngine.Builder()
.rules(dslContent)
.global("userId", "john_doe")
.global("creditThreshold", 150)
.debug(true) // Enable tracing
.build();
// Execute synchronously
Object result = engine.executeRules("UserWorkflow");
System.out.println("Result: " + result);
// Or execute asynchronously
engine.executeRulesAsync("UserWorkflow")
.thenAccept(res -> System.out.println("Async Result: " + res))
.exceptionally(throwable -> {
System.err.println("Error: " + throwable.getMessage());
return null;
});
}
}
Output
Assuming the DSL is loaded and executed:
Computed score for john_doe: 350
Result: 350
Advanced Features
Dependency Management
LWREās RuleGraphProcessor
uses topological sorting to determine rule execution order based on dependencies (e.g., #USE ... FROM
directives). It detects cycles to prevent infinite loops, ensuring robust workflows.
Circuit Breaker
The CircuitBreaker
class monitors rule failures. If a rule exceeds a failure threshold, it temporarily halts execution, preventing system overload. This is critical for high-throughput systems.
Performance Optimizations
- Cached Compilation: Rules are compiled once and cached, reducing overhead.
- Precomputed Paths: Execution order is precomputed using DAGs, minimizing runtime decisions.
- Thread-Local Pools: Context maps are reused to reduce memory allocation.
-
Parallel Execution: Independent rule groups run concurrently via
ForkJoinPool
, withScheduledExecutorService
enforcing timeouts.
Security
LWRE restricts access to dangerous classes (e.g., java.lang.Runtime
, java.io.File
) and methods (e.g., exec
, exit
). The DSLParser
validates syntax to prevent misuse, and timeouts ensure rules donāt hang.
Performance Insights
In internal tests, LWRE handles thousands of rules per second on a single thread, with parallel execution scaling linearly across cores. Compilation caching reduces rule execution latency by up to 80% after the first run.
Use Cases
- Business Rules: Implement pricing rules, discounts, or eligibility checks.
- Data Pipelines: Validate and transform data in ETL processes.
- Workflow Automation: Coordinate tasks with dependencies and retries.
Try LWRE Today!
LWRE is a lightweight, powerful solution for dynamic rule execution in Java.Itās secure and optimized for performance. I invite you to explore the GitHub repo, try the examples, and contribute ideas or feedback. If you like what you see, a ā on GitHub would help others discover this project! š
Have questions? Want to share how youāre using LWRE? Drop a comment below, open an issue on GitHub, or reach out to me directly. Letās build something amazing together! š»
Top comments (0)