Broadleaf Microservices

Key Components

By default, the Rules Engine is configured for evaluating rules written with the powerful and versatile Spring Expression Language (SpEL). For this reason, the default components have SpEL-specific implementations. If you want to learn more about SpEL, please see Spring’s official SpEL documentation.

RuleEvaluationService

This is the main component that a consumer of the Rules Engine library would inject to actually evaluate rules against objects.

SpelRuleEvaluationService

Using the configured org.springframework.expression.ExpressionParser (spelParser) bean, this service will parse each given rule string into an org.springframework.expression.Expression with added caching for compiled or interpreted expressions. All expressions are expected to be relational (i.e., evaluate to true or false). Furthermore, any interpretation or compilation of the expressions will be handled internally by the service. To include additional data required for expression evaluation or parsing, an ExpressionContext can be supplied to each method.

Caching Parsed Expressions

Parsing rule strings into expressions can be expensive, so the SpelRuleEvaluationService automatically caches the expressions after they’re parsed by the org.springframework.expression.ExpressionParser.

In most cases, the key into the parsed expression cache is just the string of the rule itself. However, if a org.springframework.expression.ParserContext is provided, its prefix and suffix are added to the rule string to form the key.

Caching the expressions provides a very significant performance increase assuming the same rule is frequently evaluated, which is typically the case.

Generating Evaluation Contexts: EvaluationContextFactory

A key element for SpEL expression evaluation is the org.springframework.expression.EvaluationContext (see the official docs here). Therefore, Broadleaf provides an EvaluationContextFactory interface intended to be used to generate an EvaluationContext for a particular "root object" (the object being evaluated) and ExpressionContext.

CachingStdEvaluationContextFactory

The default implementation of EvaluationContextFactory is CachingStdEvaluationContextFactory, which produces a basic org.springframework.expression.spel.support.StandardEvaluationContext with various information set:

  • Any configured default PropertyAccessor instances

  • Any configured default expression variables

  • Any expression variables present in the ExpressionContext

  • The root object

Caching

As its name suggests, CachingStdEvaluationContextFactory caches each created EvaluationContext to avoid having to re-create it for the same object each time.

The cache key is the combination of the root object against which expressions are to be evaluated, and the ExpressionContext.

ExpressionContext

The ExpressionContext is an extensible mechanism to include the following data for expression evaluation:

  • variables: expression variables to be injected. With the SpEL implementation, these variables are set on the org.springframework.expression.EvaluationContext before rule evaluation.

  • isMatchAnyRule: whether a root object must match all of a given collection of rules or just any of them. This is commonly used in the RuleEvaluationService to inform behavior of certain methods like findAny() and findAll().

  • limit: the size of a subset of all matching objects to return if the method is also provided a collection of objects. This is commonly used in the RuleEvaluationService to inform behavior of certain methods like findAnyN() and findFirstN(), where 'N' refers to this limit.

Note
The RuleEvaluationService accepts ExpressionContext as an argument to each of its methods as a way to customize data or behavior for each specific invocation. For this reason, there is no ExpressionContext bean registered by default and it’s therefore not technically a "component". However, if your use-case just needs the same ExpressionContext for all invocations, you can just define an ExpressionContext bean in your configuration and simply pass it to each method of RuleEvaluationService.

StandardExpressionContext

This is the default implementation of ExpressionContext where fields are immutable after creation.

A static instance StandardExpressionContext.EMPTY_EXPRESSION_CONTEXT is available for consumers that don’t have any special requirements and are comfortable with the defaults.

SpelExpressionContext and StandardSpelExpressionContext

SpelExpressionContext is an interface that extends ExpressionContext to add org.springframework.expression.ParserContext. The SpelRuleEvaluationService passes this along to org.springframework.expression.ExpressionParser to influence expression parsing/compilation routines. In the event that the expression involves expression templating, the ParserContext will be required to be present.

StandardSpelExpressionContext is the default implementation of SpelExpressionContext.

Security

To mitigate concerns about arbitrary code execution through a rule, the DataTracking library provides mechanisms to validate rules.

If you are adding a field to an entity that will store a rule string, Broadleaf recommends you annotate the field with the @RuleValidate annotation. This will cause the com.broadleafcommerce.data.tracking.core.mapping.validation.rules.RuleValidatorManager to validate those fields using the registered RuleValidator beans at the time the entity is created or updated. There are several out-of-the-box RuleValidator implementations, but you can always register your own RuleValidator beans for more customized behavior.