Rule Cascade
Usage by language

Java

rule-cascade-core for the JVM. No dependencies; works on maps and lists behind whatever JSON or YAML library the service already uses.

rule-cascade-core evaluates bundles and compiles source rulesets on any JVM. It has no dependencies: it takes documents and requests as Map<String, Object>, so it sits behind Jackson, Gson, SnakeYAML or anything else.

Supported versions: Java 17 or later (maven.compiler.release 17). CI tests JDK 17 and 21 on Linux and JDK 21 on Windows and macOS, and builds the Spring Boot example. No maximum is declared.

Install from the repository

Install the artefact into your local Maven repository, then depend on it:

git clone https://github.com/YarlisAISolutions/rule-cascade.git
mvn -f rule-cascade/packages/java/pom.xml install
<dependency>
  <groupId>io.github.yarlisaisolutions</groupId>
  <artifactId>rule-cascade-core</artifactId>
  <version>1.0.0-alpha.2</version>
</dependency>

In CI, run the same mvn install step before your build, or publish the jar to your own artefact repository. The package is io.github.yarlisaisolutions.rulecascade.

Load

Once, at start-up. A load error must stop the application.

// From a bundle compiled in CI: no YAML, no load-time checks repeated.
@SuppressWarnings("unchecked")
Map<String, Object> parsed = (Map<String, Object>) Json.parse(text);
RuleSet rules = RuleSet.fromBundle(parsed);

// Or compile source documents: document and registry are parsed YAML or JSON as maps.
RuleSet rules = RuleSet.load(document, registry, schemaLoader);

registry maps ruleset ids to documents so extends can be resolved. schemaLoader returns the document behind an entity's $ref; with null, PATH_UNKNOWN and SCHEMA_REF_UNRESOLVED are not checked.

Custom operators are attached with withOperators, and the start-up check compares them with what the manifest needs:

Map<String, CustomOperator> operators = Map.of(
        "x-starts-with-zero", args -> args.get(0) instanceof String s && s.startsWith("0"));
RuleSet rules = RuleSet.load(document, registry, schemaLoader).withOperators(operators);

List<String> missing = new ArrayList<>(rules.requiredOperators(Channel.SERVER));
missing.removeAll(operators.keySet());
if (!missing.isEmpty()) {
    throw new IllegalStateException("custom operators not registered: " + missing);
}

Evaluate

EvaluationResult result = rules.evaluate(
        EvaluationRequest.builder("Transfer", "create")
                .data(payload)                        // Map<String, Object>
                .actor(userId, roles)                 // from authentication
                .resolutions(resolutionsFromRequest)
                .build());

if (!result.allowed()) {
    throw new RuleViolationException(result);         // return result.toMap() as problem details
}
repository.save(transfer);
result.commands().forEach(outbox::publishOnce);      // de-duplicate on command.idempotencyKey()

rules.evaluate(request, Channel.CLIENT) evaluates the client channel. Evaluator evaluates a manifest received from elsewhere. A ruleset that reads ctx.now needs .ctx(Map.of("now", Instant.now().toString())) on the builder. RuleViolationException belongs to the Spring Boot example, not to the library.

Errors

WhatHow it surfacesWhat to do
A bundle that is not format 1.x, or has no usable manifestsLoadException from RuleSet.fromBundle with BUNDLE_UNSUPPORTED or BUNDLE_INVALIDLet it stop start-up
A source ruleset that fails a checkLoadException; problems() and codes() say whyLet it stop start-up; fix it in CI
A request of the wrong shapeIllegalArgumentException from the builder (no entity or operation, roles that are not strings, a resolution without a rule); EvaluationRequest.fromMap applies the full wire checkAnswer 400
A rule that cannot be evaluated, or a missing operatorNo exception: a blocking RULE-EVALUATION-ERROR findingAlert on it

More

The full API (bundles, places and data types, numbers, the engine protocol through Main engine) is in the package README. A complete service is the Spring Boot example.

Source: site/content/docs/usage/java.mdx

On this page