java.lang.Object
io.github.brantunger.unruly.api.Rule

public final class Rule extends Object
A rule: a condition that decides whether it fires, and an action that runs when it does, with a name, a priority and the language they're written in. A RulesEngine evaluates the condition during RulesEngine.run(FactStore), and fires the action when the condition is true and the engine's match policy selects the rule.

Fields:

  • ruleName: identifies the rule in error messages, exceptions and listener callbacks. Required, not blank, and unique within a rule list.
  • condition: an expression that must evaluate to a boolean. It can't assign or declare anything. Required.
  • action: an expression run when the rule fires. It changes the output object, which a language may bind to a name, such as output in MVEL. Required.
  • priority: higher values fire first. Equal priorities keep their list order, and a null priority sorts last.
  • description: free text for your own use. The engine ignores it, but listeners receive it.
  • language: the name of the expression language the condition and action are written in. null, the default, means the engine's default language.
  • enabled: whether runs use the rule. true by default.
  • validFrom and validTo: when runs use the rule, from validFrom (inclusive) until validTo (exclusive). null, the default, means no start or no end.
  • tags: names that group rules, such as a market or a product. A run given tags with RunOptions.withTags(java.util.Collection) uses only the rules that carry at least one of them. Empty by default.

A run skips a rule that is disabled, outside its validity window when the run starts, or without any of the run's tags: it doesn't evaluate the rule's condition or tell listeners about it, and its evaluation is SKIPPED. The engine still compiles every rule when it loads them, so a skipped rule's errors fail RulesEngine.load(java.util.List) too, and a rule that becomes valid later needs no reload. The time comes from the engine's clock.

A rule is immutable. Create one with builder(), whose build() rejects a rule without a name, a condition or an action. Copy a rule with a change with toBuilder(), for example rule.toBuilder().priority(5).build(). Because a rule can't change, the engine keeps the rules passed to RulesEngine.load(java.util.List), and listeners receive those same instances.

Reading rules from JSON: a binder builds rules through Rule.RuleBuilder, whose constructor is public for that. With Jackson, register one mix-in for Rule and one for its builder:

@JsonDeserialize(builder = Rule.RuleBuilder.class)
abstract class RuleMixIn {
}

@JsonPOJOBuilder(withPrefix = "")
abstract class RuleBuilderMixIn {
}

ObjectMapper mapper = JsonMapper.builder()
        .addMixIn(Rule.class, RuleMixIn.class)
        .addMixIn(Rule.RuleBuilder.class, RuleBuilderMixIn.class)
        .build();
List<Rule> rules = mapper.readValue(json, new TypeReference<List<Rule>>() { });
The code is the same for Jackson 2 (com.fasterxml.jackson.databind) and Jackson 3 (tools.jackson.databind); only the imports differ, except that Jackson 2 reads validFrom and validTo, which are Instants, only with its java.time module: .addModule(new JavaTimeModule()) from jackson-datatype-jsr310. Jackson 3 reads them without one. A rule without a name, a condition or an action fails while it's read.

equals and hashCode compare every field, including description and language. A field added in a later release takes part too.

Security: conditions and actions are code, and what a rule can reach depends on its language: in MVEL, a rule has the same access to the JVM as Java code, including processes, files and reflection. The engine applies no sandbox. A timeout stops a run between rules and when an expression returns, but can't stop inside an expression that its language doesn't interrupt. Only use rules from trusted sources.

See Also:
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static final class 
    Builds a Rule.
  • Method Summary

    Modifier and Type
    Method
    Description
    Returns a builder for a new rule.
    boolean
    equals(@Nullable Object o)
    Compares every field.
    Returns the action, run when the rule fires.
    Returns the condition, which must evaluate to a boolean and can't assign or declare anything.
    @Nullable String
    Returns the rule's description: free text for your own use, which the engine ignores but listeners receive.
    @Nullable String
    Returns the name of the expression language the condition and action are written in.
    @Nullable Integer
    Returns the rule's priority.
    Returns the rule's name, used in error messages, exceptions and listener callbacks.
    Returns the names that group the rule.
    @Nullable Instant
    Returns when runs start to use the rule.
    @Nullable Instant
    Returns when runs stop using the rule.
    int
    Combines the hash codes of every field, consistently with equals(Object).
    boolean
    Returns whether runs use the rule.
    Returns a builder that starts with this rule's fields, to create a copy with some of them changed, such as rule.toBuilder().priority(5).build().
    Lists every field, such as Rule(ruleName=prime-rate, condition=..., action=..., priority=10, description=null, language=null, enabled=true, validFrom=null, validTo=null, tags=[]).

    Methods inherited from class java.lang.Object

    clone, finalize, getClass, notify, notifyAll, wait, wait, wait
  • Method Details

    • builder

      public static Rule.RuleBuilder builder()
      Returns a builder for a new rule. The rule is enabled, with no validity window and no tags, and every other field is null until it is set.
      Returns:
      A new builder
    • toBuilder

      public Rule.RuleBuilder toBuilder()
      Returns a builder that starts with this rule's fields, to create a copy with some of them changed, such as rule.toBuilder().priority(5).build(). This rule isn't changed.
      Returns:
      A new builder holding this rule's fields
    • getRuleName

      public String getRuleName()
      Returns the rule's name, used in error messages, exceptions and listener callbacks.
      Returns:
      The name, which isn't blank
    • getCondition

      public String getCondition()
      Returns the condition, which must evaluate to a boolean and can't assign or declare anything.
      Returns:
      The condition
    • getAction

      public String getAction()
      Returns the action, run when the rule fires. It changes the output object, which a language may bind to a name, such as output in MVEL.
      Returns:
      The action
    • getPriority

      public @Nullable Integer getPriority()
      Returns the rule's priority. Higher values fire first, and null sorts last.
      Returns:
      The priority, or null
    • getDescription

      public @Nullable String getDescription()
      Returns the rule's description: free text for your own use, which the engine ignores but listeners receive.
      Returns:
      The description, or null
    • getLanguage

      public @Nullable String getLanguage()
      Returns the name of the expression language the condition and action are written in.
      Returns:
      The language's name, or null for the engine's default language
    • isEnabled

      public boolean isEnabled()
      Returns whether runs use the rule. A run skips a disabled rule.
      Returns:
      true unless the rule was built with enabled(false)
    • getValidFrom

      public @Nullable Instant getValidFrom()
      Returns when runs start to use the rule. A run that starts before it skips the rule.
      Returns:
      The start, inclusive, or null if the rule has no start
    • getValidTo

      public @Nullable Instant getValidTo()
      Returns when runs stop using the rule. A run that starts at or after it skips the rule.
      Returns:
      The end, exclusive, or null if the rule has no end
    • getTags

      public Set<String> getTags()
      Returns the names that group the rule. A run given tags uses the rule only if it carries at least one of them.
      Returns:
      The tags, in String order; unmodifiable, and empty if the rule has none
    • equals

      public boolean equals(@Nullable Object o)
      Compares every field.
      Overrides:
      equals in class Object
      Parameters:
      o - The object to compare with
      Returns:
      true if o is a Rule and every field of the two is equal
    • hashCode

      public int hashCode()
      Combines the hash codes of every field, consistently with equals(Object).
      Overrides:
      hashCode in class Object
      Returns:
      The hash code
    • toString

      public String toString()
      Lists every field, such as Rule(ruleName=prime-rate, condition=..., action=..., priority=10, description=null, language=null, enabled=true, validFrom=null, validTo=null, tags=[]).
      Overrides:
      toString in class Object
      Returns:
      The rule's fields as text