JBoss.org Community Documentation

- Prev
- Next

## Chapter 7. Rule Language Reference

## 7.1. Overview

Drools has a "native" rule language. This format is very light in terms of punctuation, and supports natural and domain specific languages via "expanders" that allow the language to morph to your problem domain. This chapter is mostly concerted with this native rule format. The diagrams used to present the syntax are known as "railroad" diagrams, and they are basically flow charts for the language terms. The technically very keen may also refer to `DRL.g` which is the Antlr3 grammar for the rule language. If you use the Rule Workbench, a lot of the rule structure is done for you with content assistance, for example, type "ru" and press ctrl+space, and it will build the rule structure for you.

### 7.1.1. A rule file

A rule file is typically a file with a .drl extension. In a DRL file you can have multiple rules, queries and functions, as well as some resource declarations like imports, globals and attributes that are assigned and used by your rules and queries. However, you are also able to spread your rules across multiple rule files (in that case, the extension .rule is suggested, but not required) - spreading rules across files can help with managing large numbers of rules. A DRL file is simply a text file.

The overall structure of a rule file is:

Example 7.1. Rules file

    package package-name

    imports

    globals

    functions

    queries

    rules

The order in which the elements are declared is not important, except for the package name that, if declared, must be the first element in the rules file. All elements are optional, so you will use only those you need. We will discuss each of them in the following sections.

### 7.1.2. What makes a rule

For the inpatients, just as an early view, a rule has the following rough structure:

    rule "name"
        attributes
        when
            LHS
        then
            RHS
    end

It's really that simple. Mostly punctuation is not needed, even the double quotes for "name" are optional, as are newlines. Attributes are simple (always optional) hints to how the rule should behave. LHS is the conditional parts of the rule, which follows a certain syntax which is covered below. RHS is basically a block that allows dialect specific semantic code to be executed.

It is important to note that white space is not important, except in the case of domain specific languages, where lines are processed one by one and spaces may be significant to the domain language.

## 7.2. Keywords

Drools 5 introduces the concept of hard and soft keywords.

Hard keywords are reserved, you cannot use any hard keyword when naming your domain objects, properties, methods, functions and other elements that are used in the rule text.

Here is the list of hard keywords that must be avoided as identifiers when writing rules:

- `true`

- `false`

- `null`

Soft keywords are just recognized in their context, enabling you to use these words in any other place if you wish, although, it is still recommended to avoid them, to avoid confusions, if possible. Here is a list of the soft keywords:

- `lock-on-active`

- `date-effective`

- `date-expires`

- `no-loop`

- `auto-focus`

- `activation-group`

- `agenda-group`

- `ruleflow-group`

- `entry-point`

- `duration`

- `package`

- `import`

- `dialect`

- `salience`

- `enabled`

- `attributes`

- `rule`

- `extend`

- when

- then

- `template`

- `query`

- `declare`

- `function`

- `global`

- `eval`

- `not`

- `in`

- `or`

- `and`

- `exists`

- `forall`

- accumulate

- collect

- from

- `action`

- `reverse`

- `result`

- `end`

- over

- `init`

Of course, you can have these (hard and soft) words as part of a method name in camel case, like notSomething() or accumulateSomething() - there are no issues with that scenario.

Although the 3 hard keywords above are unlikely to be used in your existing domain models, if you absolutely need to use them as identifiers instead of keywords, the DRL language provides the ability to escape hard keywords on rule text. To escape a word, simply enclose it in grave accents, like this:

    Holiday( `true` == "yes" ) // please note that Drools will resolve that reference to the method Holiday.isTrue()

## 7.3. Comments

Comments are sections of text that are ignored by the rule engine. They are stripped out when they are encountered, except inside semantic code blocks, like the RHS of a rule.

### 7.3.1. Single line comment

To create single line comments, you can use '//'. The parser will ignore anything in the line after the comment symbol. Example:

    rule "Testing Comments"
    when
        // this is a single line comment
        eval( true ) // this is a comment in the same line of a pattern
    then
        // this is a comment inside a semantic code block
    end

## Warning

'#' for comments has been removed.

### 7.3.2. Multi-line comment

Figure 7.1. Multi-line comment

Multi-line comments are used to comment blocks of text, both in and outside semantic code blocks. Example:

    rule "Test Multi-line Comments"
    when
        /* this is a multi-line comment
           in the left hand side of a rule */
        eval( true )
    then
        /* and this is a multi-line comment
           in the right hand side of a rule */
    end

## 7.4. Error Messages

Drools 5 introduces standardized error messages. This standardization aims to help users to find and resolve problems in a easier and faster way. In this section you will learn how to identify and interpret those error messages, and you will also receive some tips on how to solve the problems associated with them.

### 7.4.1. Message format

The standardization includes the error message format and to better explain this format, let's use the following example:

Figure 7.2. Error Message Format

1st Block: This area identifies the error code.

2nd Block: Line and column information.

3rd Block: Some text describing the problem.

4th Block: This is the first context. Usually indicates the rule, function, template or query where the error occurred. This block is not mandatory.

5th Block: Identifies the pattern where the error occurred. This block is not mandatory.

### 7.4.2. Error Messages Description

#### 7.4.2.1. 101: No viable alternative

Indicates the most common errors, where the parser came to a decision point but couldn't identify an alternative. Here are some examples:

Example 7.2.

    1: rule one
    2:   when
    3:     exists Foo()
    4:     exits Bar()
    5:   then
    6: end

The above example generates this message:

- [ERR 101] Line 4:4 no viable alternative at input 'exits' in rule one

At first glance this seems to be valid syntax, but it is not (exits != exists). Let's take a look at next example:

Example 7.3.

    1: package org.drools.examples;
    2: rule
    3:   when
    4:     Object()
    5:   then
    6:     System.out.println("A RHS");
    7: end

Now the above code generates this message:

- [ERR 101] Line 3:2 no viable alternative at input 'WHEN'

This message means that the parser encountered the token WHEN, actually a hard keyword, but it's in the wrong place since the the rule name is missing.

The error "no viable alternative" also occurs when you make a simple lexical mistake. Here is a sample of a lexical problem:

Example 7.4.

    1: rule simple_rule
    2:   when
    3:     Student( name == "Andy )
    4:   then
    5: end

The above code misses to close the quotes and because of this the parser generates this error message:

- [ERR 101] Line 0:-1 no viable alternative at input '<eof>' in rule simple_rule in pattern Student

## Note

Usually the Line and Column information are accurate, but in some cases (like unclosed quotes), the parser generates a 0:-1 position. In this case you should check whether you didn't forget to close quotes, apostrophes or parentheses.

#### 7.4.2.2. 102: Mismatched input

This error indicates that the parser was looking for a particular symbol that it didn't ﬁnd at the current input position. Here are some samples:

Example 7.5.

    1: rule simple_rule
    2:   when
    3:     foo3 : Bar(

The above example generates this message:

- [ERR 102] Line 0:-1 mismatched input '<eof>' expecting ')' in rule simple_rule in pattern Bar

To fix this problem, it is necessary to complete the rule statement.

## Note

Usually when you get a 0:-1 position, it means that parser reached the end of source.

The following code generates more than one error message:

Example 7.6.

    1: package org.drools.examples;
    2:
    3: rule "Avoid NPE on wrong syntax"
    4:   when
    5:     not( Cheese( ( type == "stilton", price == 10 ) || ( type == "brie", price == 15 ) ) from $cheeseList )
    6:   then
    7:     System.out.println("OK");
    8: end

These are the errors associated with this source:

- [ERR 102] Line 5:36 mismatched input ',' expecting ')' in rule "Avoid NPE on wrong syntax" in pattern Cheese

- [ERR 101] Line 5:57 no viable alternative at input 'type' in rule "Avoid NPE on wrong syntax"

- [ERR 102] Line 5:106 mismatched input ')' expecting 'then' in rule "Avoid NPE on wrong syntax"

Note that the second problem is related to the first. To fix it, just replace the commas (',') by AND operator ('&&').

## Note

In some situations you can get more than one error message. Try to fix one by one, starting at the first one. Some error messages are generated merely as consequences of other errors.

#### 7.4.2.3. 103: Failed predicate

A validating semantic predicate evaluated to false. Usually these semantic predicates are used to identify soft keywords. This sample shows exactly this situation:

Example 7.7.

     1: package nesting;
     2: dialect "mvel"
     3:
     4: import org.drools.compiler.Person
     5: import org.drools.compiler.Address
     6:
     7: fdsfdsfds
     8:
     9: rule "test something"
    10:   when
    11:     p: Person( name=="Michael" )
    12:   then
    13:     p.name = "other";
    14:     System.out.println(p.name);
    15: end

With this sample, we get this error message:

- [ERR 103] Line 7:0 rule 'rule_key' failed predicate: {(validateIdentifierKey(DroolsSoftKeywords.RULE))}? in rule

The fdsfdsfds text is invalid and the parser couldn't identify it as the soft keyword `rule`.

## Note

This error is very similar to 102: Mismatched input, but usually involves soft keywords.

#### 7.4.2.4. 104: Trailing semi-colon not allowed

This error is associated with the `eval` clause, where its expression may not be terminated with a semicolon. Check this example:

Example 7.8.

    1: rule simple_rule
    2:   when
    3:     eval(abc();)
    4:   then
    5: end

Due to the trailing semicolon within eval, we get this error message:

- [ERR 104] Line 3:4 trailing semi-colon not allowed in rule simple_rule

This problem is simple to fix: just remove the semi-colon.

#### 7.4.2.5. 105: Early Exit

The recognizer came to a subrule in the grammar that must match an alternative at least once, but the subrule did not match anything. Simply put: the parser has entered a branch from where there is no way out. This example illustrates it:

Example 7.9.

    1: template test_error
    2:   aa s  11;
    3: end

This is the message associated to the above sample:

- [ERR 105] Line 2:2 required (...)+ loop did not match anything at input 'aa' in template test_error

To fix this problem it is necessary to remove the numeric value as it is neither a valid data type which might begin a new template slot nor a possible start for any other rule file construct.

### 7.4.3. Other Messages

Any other message means that something bad has happened, so please contact the development team.

## 7.5. Package

A package is a collection of rules and other related constructs, such as imports and globals. The package members are typically related to each other - perhaps HR rules, for instance. A package represents a namespace, which ideally is kept unique for a given grouping of rules. The package name itself is the namespace, and is not related to files or folders in any way.

It is possible to assemble rules from multiple rule sources, and have one top level package configuration that all the rules are kept under (when the rules are assembled). Although, it is not possible to merge into the same package resources declared under different names. A single Rulebase may, however, contain multiple packages built on it. A common structure is to have all the rules for a package in the same file as the package declaration (so that is it entirely self-contained).

The following railroad diagram shows all the components that may make up a package. Note that a package must have a namespace and be declared using standard Java conventions for package names; i.e., no spaces, unlike rule names which allow spaces. In terms of the order of elements, they can appear in any order in the rule file, with the exception of the `package` statement, which must be at the top of the file. In all cases, the semicolons are optional.

Figure 7.3. package

Notice that any rule attribute (as described the section Rule Attributes) may also be written at package level, superseding the attribute's default value. The modified default may still be replaced by an attribute setting within a rule.

### 7.5.1. import

Figure 7.4. import

Import statements work like import statements in Java. You need to specify the fully qualified paths and type names for any objects you want to use in the rules. Drools automatically imports classes from the Java package of the same name, and also from the package `java.lang`.

### 7.5.2. global

Figure 7.5. global

With `global` you define global variables. They are used to make application objects available to the rules. Typically, they are used to provide data or services that the rules use, especially application services used in rule consequences, and to return data from the rules, like logs or values added in rule consequences, or for the rules to interact with the application, doing callbacks. Globals are not inserted into the Working Memory, and therefore a global should never be used to establish conditions in rules except when it has a constant immutable value. The engine cannot be notified about value changes of globals and does not track their changes. Incorrect use of globals in constraints may yield surprising results - surprising in a bad way.

If multiple packages declare globals with the same identifier they must be of the same type and all of them will reference the same global value.

In order to use globals you must:

1. Declare your global variable in your rules file and use it in rules. Example:

       global java.util.List myGlobalList;

       rule "Using a global"
       when
           eval( true )
       then
           myGlobalList.add( "Hello World" );
       end

2. Set the global value on your working memory. It is a best practice to set all global values before asserting any fact to the working memory. Example:

       List list = new ArrayList();
       KieSession kieSession = kiebase.newKieSession();
       kieSession.setGlobal( "myGlobalList", list );

Note that these are just named instances of objects that you pass in from your application to the working memory. This means you can pass in any object you want: you could pass in a service locator, or perhaps a service itself. With the new `from` element it is now common to pass a Hibernate session as a global, to allow `from` to pull data from a named Hibernate query.

One example may be an instance of a Email service. In your integration code that is calling the rule engine, you obtain your emailService object, and then set it in the working memory. In the DRL, you declare that you have a global of type EmailService, and give it the name "email". Then in your rule consequences, you can use things like email.sendSMS(number, message).

Globals are not designed to share data between rules and they should never be used for that purpose. Rules always reason and react to the working memory state, so if you want to pass data from rule to rule, assert the data as facts into the working memory.

It is strongly discouraged to set or change a global value from inside your rules. We recommend to you always set the value from your application using the working memory interface.

## 7.6. Function

Figure 7.6. function

Functions are a way to put semantic code in your rule source file, as opposed to in normal Java classes. They can't do anything more than what you can do with helper classes. (In fact, the compiler generates the helper class for you behind the scenes.) The main advantage of using functions in a rule is that you can keep the logic all in one place, and you can change the functions as needed (which can be a good or a bad thing). Functions are most useful for invoking actions on the consequence (`then`) part of a rule, especially if that particular action is used over and over again, perhaps with only differing parameters for each rule.

A typical function declaration looks like:

    function String hello(String name) {
        return "Hello "+name+"!";
    }

Note that the `function` keyword is used, even though its not really part of Java. Parameters to the function are defined as for a method, and you don't have to have parameters if they are not needed. The return type is defined just like in a regular method.

Alternatively, you could use a static method in a helper class, e.g., `Foo.hello()`. Drools supports the use of function imports, so all you would need to do is:

    import function my.package.Foo.hello

Irrespective of the way the function is defined or imported, you use a function by calling it by its name, in the consequence or inside a semantic code block. Example:

    rule "using a static function"
    when
        eval( true )
    then
        System.out.println( hello( "Bob" ) );
    end

## 7.7. Type Declaration

Figure 7.7. meta_data

Figure 7.8. type_declaration

Type declarations have two main goals in the rules engine: to allow the declaration of new types, and to allow the declaration of metadata for types.

- Declaring new types: Drools works out of the box with plain Java objects as facts. Sometimes, however, users may want to define the model directly to the rules engine, without worrying about creating models in a lower level language like Java. At other times, there is a domain model already built, but eventually the user wants or needs to complement this model with additional entities that are used mainly during the reasoning process.

- Declaring metadata: facts may have meta information associated to them. Examples of meta information include any kind of data that is not represented by the fact attributes and is consistent among all instances of that fact type. This meta information may be queried at runtime by the engine and used in the reasoning process.

### 7.7.1. Declaring New Types

To declare a new type, all you need to do is use the keyword `declare`, followed by the list of fields, and the keyword `end`. A new fact must have a list of fields, otherwise the engine will look for an existing fact class in the classpath and raise an error if not found.

Example 7.10. Declaring a new fact type: Address

    declare Address
       number : int
       streetName : String
       city : String
    end

The previous example declares a new fact type called `Address`. This fact type will have three attributes: `number`, `streetName` and `city`. Each attribute has a type that can be any valid Java type, including any other class created by the user or even other fact types previously declared.

For instance, we may want to declare another fact type `Person`:

Example 7.11. declaring a new fact type: Person

    declare Person
        name : String
        dateOfBirth : java.util.Date
        address : Address
    end

As we can see on the previous example, `dateOfBirth` is of type `java.util.Date`, from the Java API, while `address` is of the previously defined fact type Address.

You may avoid having to write the fully qualified name of a class every time you write it by using the `import` clause, as previously discussed.

Example 7.12. Avoiding the need to use fully qualified class names by using import

    import java.util.Date

    declare Person
        name : String
        dateOfBirth : Date
        address : Address
    end

When you declare a new fact type, Drools will, at compile time, generate bytecode that implements a Java class representing the fact type. The generated Java class will be a one-to-one Java Bean mapping of the type definition. So, for the previous example, the generated Java class would be:

Example 7.13. generated Java class for the previous Person fact type declaration

    public class Person implements Serializable {
        private String name;
        private java.util.Date dateOfBirth;
        private Address address;

        // empty constructor
        public Person() {...}

        // constructor with all fields
        public Person( String name, Date dateOfBirth, Address address ) {...}

        // if keys are defined, constructor with keys
        public Person( ...keys... ) {...}

        // getters and setters
        // equals/hashCode
        // toString
    }

Since the generated class is a simple Java class, it can be used transparently in the rules, like any other fact.

Example 7.14. Using the declared types in rules

    rule "Using a declared Type"
    when
        $p : Person( name == "Bob" )
    then
        // Insert Mark, who is Bob's mate.
        Person mark = new Person();
        mark.setName("Mark");
        insert( mark );
    end

### 7.7.2. Declaring Metadata

Metadata may be assigned to several different constructions in Drools: fact types, fact attributes and rules. Drools uses the at sign ('@') to introduce metadata, and it always uses the form:

    @metadata_key( metadata_value )

The parenthesized metadata_value is optional.

For instance, if you want to declare a metadata attribute like `author`, whose value is Bob, you could simply write:

Example 7.15. Declaring a metadata attribute

    @author( Bob )

Drools allows the declaration of any arbitrary metadata attribute, but some will have special meaning to the engine, while others are simply available for querying at runtime. Drools allows the declaration of metadata both for fact types and for fact attributes. Any metadata that is declared before the attributes of a fact type are assigned to the fact type, while metadata declared after an attribute are assigned to that particular attribute.

Example 7.16. Declaring metadata attributes for fact types and attributes

    import java.util.Date

    declare Person
        @author( Bob )
        @dateOfCreation( 01-Feb-2009 )

        name : String @key @maxLength( 30 )
        dateOfBirth : Date
        address : Address
    end

In the previous example, there are two metadata items declared for the fact type (`@author` and `@dateOfCreation`) and two more defined for the name attribute (`@key` and `@maxLength`). Please note that the `@key` metadata has no required value, and so the parentheses and the value were omitted.:

#### 7.7.2.1. Predefined class level annotations

Some annotations have predefined semantics that are interpreted by the engine. The following is a list of some of these predefined annotations and their meaning.

##### 7.7.2.1.1. @role( <fact | event> )

The @role annotation defines how the engine should handle instances of that type: either as regular facts or as events. It accepts two possible values:

- fact : this is the default, declares that the type is to be handled as a regular fact.

- event : declares that the type is to be handled as an event.

The following example declares that the fact type StockTick in a stock broker application is to be handled as an event.

Example 7.17. declaring a fact type as an event

    import some.package.StockTick

    declare StockTick
        @role( event )
    end

The same applies to facts declared inline. If StockTick was a fact type declared in the DRL itself, instead of a previously existing class, the code would be:

Example 7.18. declaring a fact type and assigning it the event role

    declare StockTick
        @role( event )

        datetime : java.util.Date
        symbol : String
        price : double
    end

##### 7.7.2.1.2. @typesafe( <boolean> )

By default all type declarations are compiled with type safety enabled; @typesafe( false ) provides a means to override this behaviour by permitting a fall-back, to type unsafe evaluation where all constraints are generated as MVEL constraints and executed dynamically. This can be important when dealing with collections that do not have any generics or mixed type collections.

##### 7.7.2.1.3. @timestamp( <attribute name> )

Every event has an associated timestamp assigned to it. By default, the timestamp for a given event is read from the Session Clock and assigned to the event at the time the event is inserted into the working memory. Although, sometimes, the event has the timestamp as one of its own attributes. In this case, the user may tell the engine to use the timestamp from the event's attribute instead of reading it from the Session Clock.

    @timestamp( <attributeName> )

To tell the engine what attribute to use as the source of the event's timestamp, just list the attribute name as a parameter to the @timestamp tag.

Example 7.19. declaring the VoiceCall timestamp attribute

    declare VoiceCall
        @role( event )
        @timestamp( callDateTime )
    end

##### 7.7.2.1.4. @duration( <attribute name> )

Drools supports both event semantics: point-in-time events and interval-based events. A point-in-time event is represented as an interval-based event whose duration is zero. By default, all events have duration zero. The user may attribute a different duration for an event by declaring which attribute in the event type contains the duration of the event.

    @duration( <attributeName> )

So, for our VoiceCall fact type, the declaration would be:

Example 7.20. declaring the VoiceCall duration attribute

    declare VoiceCall
        @role( event )
        @timestamp( callDateTime )
        @duration( callDuration )
    end

##### 7.7.2.1.5. @expires( <time interval> )

## Important

This tag is only considered when running the engine in STREAM mode. Also, additional discussion on the effects of using this tag is made on the Memory Management section. It is included here for completeness.

Events may be automatically expired after some time in the working memory. Typically this happens when, based on the existing rules in the knowledge base, the event can no longer match and activate any rules. Although, it is possible to explicitly define when an event should expire.

    @expires( <timeOffset> )

The value of timeOffset is a temporal interval in the form:

    [#d][#h][#m][#s][#[ms]]

Where [ ] means an optional parameter and # means a numeric value.

So, to declare that the VoiceCall facts should be expired after 1 hour and 35 minutes after they are inserted into the working memory, the user would write:

Example 7.21. declaring the expiration offset for the VoiceCall events

    declare VoiceCall
        @role( event )
        @timestamp( callDateTime )
        @duration( callDuration )
        @expires( 1h35m )
    end

The @expires policy will take precedence and override the implicit expiration offset calculated from temporal constraints and sliding windows in the knowledge base.

##### 7.7.2.1.6. @propertyChangeSupport

Facts that implement support for property changes as defined in the Javabean(tm) spec, now can be annotated so that the engine register itself to listen for changes on fact properties. The boolean parameter that was used in the insert() method in the Drools 4 API is deprecated and does not exist in the drools-api module.

Example 7.22. @propertyChangeSupport

    declare Person
      @propertyChangeSupport
    end

##### 7.7.2.1.7. @propertyReactive

Make this type property reactive. See Fine grained property change listeners section for details.

#### 7.7.2.2. Predefined attribute level annotations

As noted before, Drools also supports annotations in type attributes. Here is a list of predefined attribute annotations.

##### 7.7.2.2.1. @key

Declaring an attribute as a key attribute has 2 major effects on generated types:

1. The attribute will be used as a key identifier for the type, and as so, the generated class will implement the equals() and hashCode() methods taking the attribute into account when comparing instances of this type.

2. Drools will generate a constructor using all the key attributes as parameters.

For instance:

Example 7.23. example of @key declarations for a type

    declare Person
        firstName : String @key
        lastName : String @key
        age : int
    end

For the previous example, Drools will generate equals() and hashCode() methods that will check the firstName and lastName attributes to determine if two instances of Person are equal to each other, but will not check the age attribute. It will also generate a constructor taking firstName and lastName as parameters, allowing one to create instances with a code like this:

Example 7.24. creating an instance using the key constructor

    Person person = new Person( "John", "Doe" );

##### 7.7.2.2.2. @position

Patterns support positional arguments on type declarations.

Positional arguments are ones where you don't need to specify the field name, as the position maps to a known named field. i.e. Person( name == "mark" ) can be rewritten as Person( "mark"; ). The semicolon ';' is important so that the engine knows that everything before it is a positional argument. Otherwise we might assume it was a boolean expression, which is how it could be interpreted after the semicolon. You can mix positional and named arguments on a pattern by using the semicolon ';' to separate them. Any variables used in a positional that have not yet been bound will be bound to the field that maps to that position.

    declare Cheese
        name : String
        shop : String
        price : int
    end

The default order is the declared order, but this can be overridden using @position

    declare Cheese
        name : String @position(1)
        shop : String @position(2)
        price : int @position(0)
    end

The @Position annotation, in the org.drools.definition.type package, can be used to annotate original pojos on the classpath. Currently only fields on classes can be annotated. Inheritance of classes is supported, but not interfaces of methods yet.

Example patterns, with two constraints and a binding. Remember semicolon ';' is used to differentiate the positional section from the named argument section. Variables and literals and expressions using just literals are supported in positional arguments, but not variables.

    Cheese( "stilton", "Cheese Shop", p; )
    Cheese( "stilton", "Cheese Shop"; p : price )
    Cheese( "stilton"; shop == "Cheese Shop", p : price )
    Cheese( name == "stilton"; shop == "Cheese Shop", p : price )

@Position is inherited when beans extend each other; while not recommended, two fields may have the same @position value, and not all consecutive values need be declared. If a @position is repeated, the conflict is solved using inheritance (fields in the superclass have the precedence) and the declaration order. If a @position value is missing, the first field without an explicit @position (if any) is selected to fill the gap. As always, conflicts are resolved by inheritance and declaration order.

    declare Cheese
        name : String
        shop : String @position(2)
        price : int @position(0)
    end

    declare SeasonedCheese extends Cheese
        year : Date @position(0)
        origin : String @position(6)
        country : String
    end

In the example, the field order would be : price (@position 0 in the superclass), year (@position 0 in the subclass), name (first field with no @position), shop (@position 2), country (second field without @position), origin.

### 7.7.3. Declaring Metadata for Existing Types

Drools allows the declaration of metadata attributes for existing types in the same way as when declaring metadata attributes for new fact types. The only difference is that there are no fields in that declaration.

For instance, if there is a class org.drools.examples.Person, and one wants to declare metadata for it, it's possible to write the following code:

Example 7.25. Declaring metadata for an existing type

    import org.drools.examples.Person

    declare Person
        @author( Bob )
        @dateOfCreation( 01-Feb-2009 )
    end

Instead of using the import, it is also possible to reference the class by its fully qualified name, but since the class will also be referenced in the rules, it is usually shorter to add the import and use the short class name everywhere.

Example 7.26. Declaring metadata using the fully qualified class name

    declare org.drools.examples.Person
        @author( Bob )
        @dateOfCreation( 01-Feb-2009 )
    end

### 7.7.4. Parametrized constructors for declared types

Generate constructors with parameters for declared types.

Example: for a declared type like the following:

    declare Person
        firstName : String @key
        lastName : String @key
        age : int
    end

The compiler will implicitly generate 3 constructors: one without parameters, one with the @key fields, and one with all fields.

    Person() // parameterless constructor
    Person( String firstName, String lastName )
    Person( String firstName, String lastName, int age )

### 7.7.5. Non Typesafe Classes

@typesafe( <boolean>) has been added to type declarations. By default all type declarations are compiled with type safety enabled; @typesafe( false ) provides a means to override this behaviour by permitting a fall-back, to type unsafe evaluation where all constraints are generated as MVEL constraints and executed dynamically. This can be important when dealing with collections that do not have any generics or mixed type collections.

### 7.7.6. Accessing Declared Types from the Application Code

Declared types are usually used inside rules files, while Java models are used when sharing the model between rules and applications. Although, sometimes, the application may need to access and handle facts from the declared types, especially when the application is wrapping the rules engine and providing higher level, domain specific user interfaces for rules management.

In such cases, the generated classes can be handled as usual with the Java Reflection API, but, as we know, that usually requires a lot of work for small results. Therefore, Drools provides a simplified API for the most common fact handling the application may want to do.

The first important thing to realize is that a declared fact will belong to the package where it was declared. So, for instance, in the example below, `Person` will belong to the `org.drools.examples` package, and so the fully qualified name of the generated class will be `org.drools.examples.Person`.

Example 7.27. Declaring a type in the org.drools.examples package

    package org.drools.examples

    import java.util.Date

    declare Person
        name : String
        dateOfBirth : Date
        address : Address
    end

Declared types, as discussed previously, are generated at knowledge base compilation time, i.e., the application will only have access to them at application run time. Therefore, these classes are not available for direct reference from the application.

Drools then provides an interface through which users can handle declared types from the application code: `org.drools.definition.type.FactType`. Through this interface, the user can instantiate, read and write fields in the declared fact types.

Example 7.28. Handling declared fact types through the API

    // get a reference to a knowledge base with a declared type:
    KieBase kbase = ...

    // get the declared FactType
    FactType personType = kbase.getFactType( "org.drools.examples",
                                             "Person" );

    // handle the type as necessary:
    // create instances:
    Object bob = personType.newInstance();

    // set attributes values
    personType.set( bob,
                    "name",
                    "Bob" );
    personType.set( bob,
                    "age",
                    42 );

    // insert fact into a session
    KieSession ksession = ...
    ksession.insert( bob );
    ksession.fireAllRules();

    // read attributes
    String name = personType.get( bob, "name" );
    int age = personType.get( bob, "age" );

The API also includes other helpful methods, like setting all the attributes at once, reading values from a Map, or reading all attributes at once, into a Map.

Although the API is similar to Java reflection (yet much simpler to use), it does not use reflection underneath, relying on much more performant accessors implemented with generated bytecode.

### 7.7.7. Type Declaration 'extends'

Type declarations now support 'extends' keyword for inheritance

In order to extend a type declared in Java by a DRL declared subtype, repeat the supertype in a declare statement without any fields.

    b org.people.Person

    declare Person end

    declare Student extends Person
        school : String
    end

    declare LongTermStudent extends Student
        years : int
        course : String
    end

### 7.7.8. Traits

WARNING : this feature is still experimental and subject to changes

The same fact may have multiple dynamic types which do not fit naturally in a class hierarchy. Traits allow to model this very common scenario. A trait is an interface that can be applied (and eventually removed) to an individual object at runtime. To create a trait rather than a traditional bean, one has to declare them explicitly as in the following example:

Example 7.29.

    declare trait GoldenCustomer
        // fields will map to getters/setters
        code     : String
        balance  : long
        discount : int
        maxExpense : long
    end

At runtime, this declaration results in an interface, which can be used to write patterns, but can not be instantiated directly. In order to apply a trait to an object, we provide the new don keyword, which can be used as simply as this:

Example 7.30.

    when
        $c : Customer()
    then
        GoldenCustomer gc = don( $c, GoldenCustomer.class );
    end

when a core object dons a trait, a proxy class is created on the fly (one such class will be generated lazily for each core/trait class combination). The proxy instance, which wraps the core object and implements the trait interface, is inserted automatically and will possibly activate other rules. An immediate advantage of declaring and using interfaces, getting the implementation proxy for free from the engine, is that multiple inheritance hierarchies can be exploited when writing rules. The core classes, however, need not implement any of those interfaces statically, also facilitating the use of legacy classes as cores. In fact, any object can don a trait, provided that they are declared as @Traitable. Notice that this annotation used to be optional, but now is mandatory.

Example 7.31.

    import org.drools.core.factmodel.traits.Traitable;
    declare Customer
        @Traitable
        code    : String
        balance : long
    end

The only connection between core classes and trait interfaces is at the proxy level: a trait is not specifically tied to a core class. This means that the same trait can be applied to totally different objects. For this reason, the trait does not transparently expose the fields of its core object. So, when writing a rule using a trait interface, only the fields of the interface will be available, as usual. However, any field in the interface that corresponds to a core object field, will be mapped by the proxy class:

Example 7.32.

    when
        $o: OrderItem( $p : price, $code : custCode )
        $c: GoldenCustomer( code == $code, $a : balance, $d: discount )
    then
        $c.setBalance( $a - $p*$d );
    end

In this case, the code and balance would be read from the underlying Customer object. Likewise, the setAccount will modify the underlying object, preserving a strongly typed access to the data structures. A hard field must have the same name and type both in the core class and all donned interfaces. The name is used to establish the mapping: if two fields have the same name, then they must also have the same declared type. The annotation @org.drools.core.factmodel.traits.Alias allows to relax this restriction. If an @Alias is provided, its value string will be used to resolve mappings instead of the original field name. @Alias can be applied both to traits and core beans.

Example 7.33.

    import org.drools.core.factmodel.traits.*;
    declare trait GoldenCustomer
        balance : long @Alias( "org.acme.foo.accountBalance" )
    end

    declare Person
        @Traitable
        name : String
        savings : long @Alias( "org.acme.foo.accountBalance" )
    end

    when
        GoldenCustomer( balance > 1000 ) // will react to new Person( 2000 )
    then
    end

More work is being done on reaxing this constraint (see the experimental section on "logical" traits later). Now, one might wonder what happens when a core class does NOT provide the implementation for a field defined in an interface. We call hard fields those trait fields which are also core fields and thus readily available, while we define soft those fields which are NOT provided by the core class. Hidden fields, instead, are fields in the core class not exposed by the interface.

So, while hard field management is intuitive, there remains the problem of soft and hidden fields. Hidden fields are normally only accessible using the core class directly. However, the "fields" Map can be used on a trait interface to access a hidden field. If the field can't be resolved, null will be returned. Notice that this feature is likely to change in the future.

Example 7.34.

    when
        $sc : GoldenCustomer( fields[ "age" ] > 18 )  // age is declared by the underlying core class, but not by GoldenCustomer
    then

Soft fields, instead, are stored in a Map-like data structure that is specific to each core object and referenced by the proxy(es), so that they are effectively shared even when an object dons multiple traits.

Example 7.35.

    when
        $sc : GoldenCustomer( $c : code, // hard getter
                              $maxExpense : maxExpense > 1000 // soft getter
        )
    then
        $sc.setDiscount( ... ); // soft setter
    end

A core object also holds a reference to all its proxies, so that it is possible to track which type(s) have been added to an object, using a sort of dynamic "instanceof" operator, which we called isA. The operator can accept a String, a class literal or a list of class literals. In the latter case, the constraint is satisfied only if all the traits have been donned.

Example 7.36.

    $sc : GoldenCustomer( $maxExpense : maxExpense > 1000,
                          this isA "SeniorCustomer", this isA [ NationalCustomer.class, OnlineCustomer.class ]
    )

Eventually, the business logic may require that a trait is removed from a wrapped object. To this end, we provide two options. The first is a "logical don", which will result in a logical insertion of the proxy resulting from the traiting operation. The TMS will ensure that the trait is removed when its logical support is removed in the first place.

Example 7.37.

    then
        don( $x, // core object
             Customer.class, // trait class
             true // optional flag for logical insertion
        )

The second is the use of the "shed" keyword, which causes the removal of any type that is a subtype (or equivalent) of the one passed as an argument. Notice that, as of version 5.5, shed would only allow to remove a single specific trait.

Example 7.38.

    then
        Thing t = shed( $x, GoldenCustomer.class ) // also removes any trait that

This operation returns another proxy implementing the org.drools.core.factmodel.traits.Thing interface, where the getFields() and getCore() methods are defined. Internally, in fact, all declared traits are generated to extend this interface (in addition to any others specified). This allows to preserve the wrapper with the soft fields which would otherwise be lost.

A trait and its proxies are also correlated in another way. Starting from version 5.6, whenever a core object is "modified", its proxies are "modified" automatically as well, to allow trait-based patterns to react to potential changes in hard fields. Likewise, whenever a trait proxy (mached by a trait pattern) is modified, the modification is propagated to the core class and the other traits. Morover, whenever a don operation is performed, the core object is also modified automatically, to reevaluate any "isA" operation which may be triggered.

Potentially, this may result in a high number of modifications, impacting performance (and correctness) heavily. So two solutions are currently implemented. First, whenever a core object is modified, only the most specific traits (in the sense of inheritance between trait interfaces) are updated and an internal blocking mechanism is in place to ensure that each potentially matching pattern is evaluated once and only once. So, in the following situation:

    declare trait GoldenCustomer end
    declare trait NationalGoldenustomer extends GoldenCustomer end
    declare trait SeniorGoldenCustomer extends GoldenCustomer end

a modification of an object that is both a GoldenCustomer, a NationalGoldenCustomer and a SeniorGoldenCustomer wold cause only the latter two proxies to be actually modified. The first would match any pattern for GoldenCustomer and NationalGoldenCustomer; the latter would instead be prevented from rematching GoldenCustomer, but would be allowed to match SeniorGoldenCustomer patterns. It is not necessary, instead, to modify the GoldenCustomer proxy since it is already covered by at least one other more specific trait.

The second method, up to the usr, is to mark traits as @PropertyReactive. Property reactivity is trait-enabled and takes into account the trait field mappings, so to block unnecessary propagations.

#### 7.7.8.1. Cascading traits

WARNING : This feature is extremely experimental and subject to changes

Normally, a hard field must be exposed with its original type by all traits donned by an object, to prevent situations such as

Example 7.39.

    declare Person
      @Traitable
      name : String
      id : String
    end

    declare trait Customer
      id : String
    end

    declare trait Patient
      id : long  // Person can't don Patient, or an exception will be thrown
    end

Should a Person don both Customer and Patient, the type of the hard field id would be ambiguous. However, consider the following example, where GoldenCustomers refer their best friends so that they become Customers as well:

Example 7.40.

    declare Person
      @Traitable( logical=true )
      bestFriend : Person
    end

    declare trait Customer end

    declare trait GoldenCustomer extends Customer
      refers : Customer @Alias( "bestFriend" )
    end

Aside from the @Alias, a Person-as-GoldenCustomer's best friend might be compatible with the requirements of the trait GoldenCustomer, provided that they are some kind of Customer themselves. Marking a Person as "logically traitable" - i.e. adding the annotation @Traitable( logical = true ) - will instruct the engine to try and preserve the logical consistency rather than throwing an exception due to a hard field with different type declarations (Person vs Customer). The following operations would then work:

Example 7.41.

    Person p1 = new Person();
    Person p2 = new Person();
    p1.setBestFriend( p2 );
    ...
    Customer c2 = don( p2, Customer.class );
    ...
    GoldenCustomer gc1 = don( p1, GoldenCustomer.class );
    ...
    p1.getBestFriend(); // returns p2
    gc1.getRefers(); // returns c2, a Customer proxy wrapping p2

Notice that, by the time p1 becomes GoldenCustomer, p2 must have already become a Customer themselves, otherwise a runtime exception will be thrown since the very definition of GoldenCustomer would have been violated.

In some cases, however, one might want to infer, rather than verify, that p2 is a Customer by virtue that p1 is a GoldenCustomer. This modality can be enabled by marking Customer as "logical", using the annotation @org.drools.core.factmodel.traits.Trait( logical = true ). In this case, should p2 not be a Customer by the time that p1 becomes a GoldenCustomer, it will be automatically don the trait Customer to preserve the logical integrity of the system.

Notice that the annotation on the core class enables the dynamic type management for its fields, whereas the annotation on the traits determines whether they will be enforced as integrity constraints or cascaded dynamically.

Example 7.42.

    import org.drools.factmodel.traits.*;

    declare trait Customer
        @Trait( logical = true )
    end

## 7.8. Rule

Figure 7.9. rule

A rule specifies that when a particular set of conditions occur, specified in the Left Hand Side (LHS), then do what queryis specified as a list of actions in the Right Hand Side (RHS). A common question from users is "Why use when instead of if?" "When" was chosen over "if" because "if" is normally part of a procedural execution flow, where, at a specific point in time, a condition is to be checked. In contrast, "when" indicates that the condition evaluation is not tied to a specific evaluation sequence or point in time, but that it happens continually, at any time during the life time of the engine; whenever the condition is met, the actions are executed.

A rule must have a name, unique within its rule package. If you define a rule twice in the same DRL it produces an error while loading. If you add a DRL that includes a rule name already in the package, it replaces the previous rule. If a rule name is to have spaces, then it will need to be enclosed in double quotes (it is best to always use double quotes).

Attributes - described below - are optional. They are best written one per line.

The LHS of the rule follows the `when` keyword (ideally on a new line), similarly the RHS follows the `then` keyword (again, ideally on a newline). The rule is terminated by the keyword `end`. Rules cannot be nested.

Example 7.43. Rule Syntax Overview

    rule "<name>"
        <attribute>*
    when
        <conditional element>*
    then
        <action>*
    end

Example 7.44. A simple rule

    rule "Approve if not rejected"
      salience -100
      agenda-group "approval"
        when
            not Rejection()
            p : Policy(approved == false, policyState:status)
            exists Driver(age > 25)
            Process(status == policyState)
        then
            log("APPROVED: due to no objections.");
            p.setApproved(true);
    end

### 7.8.1. Rule Attributes

Rule attributes provide a declarative way to influence the behavior of the rule. Some are quite simple, while others are part of complex subsystems such as ruleflow. To get the most from Drools you should make sure you have a proper understanding of each attribute.

Figure 7.10. rule attributes

`no-loop`

  default value: `false`

  type: Boolean

  When a rule's consequence modifies a fact it may cause the rule to activate again, causing an infinite loop. Setting no-loop to true will skip the creation of another Activation for the rule with the current set of facts.

`ruleflow-group`

  default value: N/A

  type: String

  Ruleflow is a Drools feature that lets you exercise control over the firing of rules. Rules that are assembled by the same ruleflow-group identifier fire only when their group is active.

`lock-on-active`

  default value: `false`

  type: Boolean

  Whenever a ruleflow-group becomes active or an agenda-group receives the focus, any rule within that group that has lock-on-active set to true will not be activated any more; irrespective of the origin of the update, the activation of a matching rule is discarded. This is a stronger version of no-loop, because the change could now be caused not only by the rule itself. It's ideal for calculation rules where you have a number of rules that modify a fact and you don't want any rule re-matching and firing again. Only when the ruleflow-group is no longer active or the agenda-group loses the focus those rules with lock-on-active set to true become eligible again for their activations to be placed onto the agenda.

`salience`

  default value: `0`

  type: integer

  Each rule has an integer salience attribute which defaults to zero and can be negative or positive. Salience is a form of priority where rules with higher salience values are given higher priority when ordered in the Activation queue.

  Drools also supports dynamic salience where you can use an expression involving bound variables.

  Example 7.45. Dynamic Salience

      rule "Fire in rank order 1,2,.."
              salience( -$rank )
          when
              Element( $rank : rank,... )
          then
              ...
      end

`agenda-group`

  default value: MAIN

  type: String

  Agenda groups allow the user to partition the Agenda providing more execution control. Only rules in the agenda group that has acquired the focus are allowed to fire.

`auto-focus`

  default value: `false`

  type: Boolean

  When a rule is activated where the `auto-focus` value is true and the rule's agenda group does not have focus yet, then it is given focus, allowing the rule to potentially fire.

`activation-group`

  default value: N/A

  type: String

  Rules that belong to the same activation-group, identified by this attribute's string value, will only fire exclusively. More precisely, the first rule in an activation-group to fire will cancel all pending activations of all rules in the group, i.e., stop them from firing.

  Note: This used to be called Xor group, but technically it's not quite an Xor. You may still hear people mention Xor group; just swap that term in your mind with activation-group.

`dialect`

  default value: as specified by the package

  type: String

  possible values: "java" or "mvel"

  The dialect species the language to be used for any code expressions in the LHS or the RHS code block. Currently two dialects are available, Java and MVEL. While the dialect can be specified at the package level, this attribute allows the package definition to be overridden for a rule.

`date-effective`

  default value: N/A

  type: String, containing a date and time definition

  A rule can only activate if the current date and time is after date-effective attribute.

`date-expires`

  default value: N/A

  type: String, containing a date and time definition

  A rule cannot activate if the current date and time is after the date-expires attribute.

`duration`

  default value: no default value

  type: long

  The duration dictates that the rule will fire after a specified duration, if it is still true.

Example 7.46. Some attribute examples

    rule "my rule"
      salience 42
      agenda-group "number 1"
        when ...

### 7.8.2. Timers and Calendars

Rules now support both interval and cron based timers, which replace the now deprecated duration attribute.

Example 7.47. Sample timer attribute uses

    timer ( int: <initial delay> <repeat interval>? )
    timer ( int: 30s )
    timer ( int: 30s 5m )

    timer ( cron: <cron expression> )
    timer ( cron:* 0/15 * * * ? )

Interval (indicated by "int:") timers follow the semantics of java.util.Timer objects, with an initial delay and an optional repeat interval. Cron (indicated by "cron:") timers follow standard Unix cron expressions:

Example 7.48. A Cron Example

    rule "Send SMS every 15 minutes"
        timer (cron:* 0/15 * * * ?)
    when
        $a : Alarm( on == true )
    then
        channels[ "sms" ].insert( new Sms( $a.mobileNumber, "The alarm is still on" );
    end

A rule controlled by a timer becomes active when it matches, and once for each individual match. Its consequence is executed repeatedly, according to the timer's settings. This stops as soon as the condition doesn't match any more.

Consequences are executed even after control returns from a call to fireUntilHalt. Moreover, the Engine remains reactive to any changes made to the Working Memory. For instance, removing a fact that was involved in triggering the timer rule's execution causes the repeated execution to terminate, or inserting a fact so that some rule matches will cause that rule to fire. But the Engine is not continually active, only after a rule fires, for whatever reason. Thus, reactions to an insertion done asynchronously will not happen until the next execution of a timer-controlled rule. Disposing a session puts an end to all timer activity.

Conversely when the rule engine runs in passive mode (i.e.: using fireAllRules instead of fireUntilHalt) by default it doesn't fire consequences of timed rules unless fireAllRules isn't invoked again. However it is possible to change this default behavior by configuring the KieSession with a `TimedRuleExectionOption` as shown in the following example.

Example 7.49. Configuring a KieSession to automatically execute timed rules

    KieSessionConfiguration ksconf = KieServices.Factory.get().newKieSessionConfiguration();
    ksconf.setOption( TimedRuleExectionOption.YES );
    KSession ksession = kbase.newKieSession(ksconf, null);

It is also possible to have a finer grained control on the timed rules that have to be automatically executed. To do this it is necessary to set a `FILTERED` `TimedRuleExectionOption` that allows to define a callback to filter those rules, as done in the next example.

Example 7.50. Configuring a filter to choose which timed rules should be automatically executed

    KieSessionConfiguration ksconf = KieServices.Factory.get().newKieSessionConfiguration();
    conf.setOption( new TimedRuleExectionOption.FILTERED(new TimedRuleExecutionFilter() {
        public boolean accept(Rule[] rules) {
            return rules[0].getName().equals("MyRule");
        }
    }) );

For what regards interval timers it is also possible to define both the delay and interval as an expression instead of a fixed value. To do that it is necessary to use an expression timer (indicated by "expr:") as in the following example:

Example 7.51. An Expression Timer Example

    declare Bean
        delay   : String = "30s"
        period  : long = 60000
    end

    rule "Expression timer"
        timer( expr: $d, $p )
    when
        Bean( $d : delay, $p : period )
    then
    end

The expressions, $d and $p in this case, can use any variable defined in the pattern matching part of the rule and can be any String that can be parsed in a time duration or any numeric value that will be internally converted in a long representing a duration expressed in milliseconds.

Both interval and expression timers can have 3 optional parameters named "start", "end" and "repeat-limit". When one or more of these parameters are used the first part of the timer definition must be followed by a semicolon ';' and the parameters have to be separated by a comma ',' as in the following example:

Example 7.52. An Interval Timer with a start and an end

    timer (int: 30s 10s; start=3-JAN-2010, end=5-JAN-2010)

The value for start and end parameters can be a Date, a String representing a Date or a long, or more in general any Number, that will be transformed in a Java Date applying the following conversion:

    new Date( ((Number) n).longValue() )

Conversely the repeat-limit can be only an integer and it defines the maximum number of repetitions allowed by the timer. If both the end and the repeat-limit parameters are set the timer will stop when the first of the two will be matched.

The using of the start parameter implies the definition of a phase for the timer, where the beginning of the phase is given by the start itself plus the eventual delay. In other words in this case the timed rule will then be scheduled at times:

    start + delay + n*period

for up to repeat-limit times and no later than the end timestamp (whichever first). For instance the rule having the following interval timer

    timer ( int: 30s 1m; start="3-JAN-2010" )

will be scheduled at the 30th second of every minute after the midnight of the 3-JAN-2010. This also means that if for example you turn the system on at midnight of the 3-FEB-2010 it won't be scheduled immediately but will preserve the phase defined by the timer and so it will be scheduled for the first time 30 seconds after the midnight. If for some reason the system is paused (e.g. the session is serialized and then deserialized after a while) the rule will be scheduled only once to recover from missing activations (regardless of how many activations we missed) and subsequently it will be scheduled again in phase with the timer.

Calendars are used to control when rules can fire. The Calendar API is modelled on Quartz:

Example 7.53. Adapting a Quartz Calendar

    Calendar weekDayCal = QuartzHelper.quartzCalendarAdapter(org.quartz.Calendar quartzCal)

Calendars are registered with the KieSession:

Example 7.54. Registering a Calendar

    ksession.getCalendars().set( "weekday", weekDayCal );

They can be used in conjunction with normal rules and rules including timers. The rule attribute "calendars" may contain one or more comma-separated calendar names written as string literals.

Example 7.55. Using Calendars and Timers together

    rule "weekdays are high priority"
       calendars "weekday"
       timer (int:0 1h)
    when
        Alarm()
    then
        send( "priority high - we have an alarm" );
    end

    rule "weekend are low priority"
       calendars "weekend"
       timer (int:0 4h)
    when
        Alarm()
    then
        send( "priority low - we have an alarm" );
    end

### 7.8.3. Left Hand Side (when) syntax

#### 7.8.3.1. What is the Left Hand Side?

The Left Hand Side (LHS) is a common name for the conditional part of the rule. It consists of zero or more Conditional Elements. If the LHS is empty, it will be considered as a condition element that is always true and it will be activated once, when a new WorkingMemory session is created.

Figure 7.11. Left Hand Side

Example 7.56. Rule without a Conditional Element

    rule "no CEs"
    when
        // empty
    then
        ... // actions (executed once)
    end

    // The above rule is internally rewritten as:

    rule "eval(true)"
    when
        eval( true )
    then
        ... // actions (executed once)
    end

Conditional elements work on one or more patterns (which are described below). The most common conditional element is "`and"`. Therefore it is implicit when you have multiple patterns in the LHS of a rule that are not connected in any way:

Example 7.57. Implicit and

    rule "2 unconnected patterns"
    when
        Pattern1()
        Pattern2()
    then
        ... // actions
    end

    // The above rule is internally rewritten as:

    rule "2 and connected patterns"
    when
        Pattern1()
        and Pattern2()
    then
        ... // actions
    end

## Note

An "`and"` cannot have a leading declaration binding (unlike for example `or`). This is obvious, since a declaration can only reference a single fact at a time, and when the "`and"` is satisfied it matches both facts - so which fact would the declaration bind to?

    // Compile error
    $person : (Person( name == "Romeo" ) and Person( name == "Juliet"))

#### 7.8.3.2. Pattern (conditional element)

##### 7.8.3.2.1. What is a pattern?

A pattern element is the most important Conditional Element. It can potentially match on each fact that is inserted in the working memory.

A pattern contains of zero or more constraints and has an optional pattern binding. The railroad diagram below shows the syntax for this.

Figure 7.12. Pattern

In its simplest form, with no constraints, a pattern matches against a fact of the given type. In the following case the type is `Cheese`, which means that the pattern will match against all `Person` objects in the Working Memory:

    Person()

The type need not be the actual class of some fact object. Patterns may refer to superclasses or even interfaces, thereby potentially matching facts from many different classes.

    Object() // matches all objects in the working memory

Inside of the pattern parenthesis is where all the action happens: it defines the constraints for that pattern. For example, with a age related constraint:

    Person( age == 100 )

## Note

For backwards compatibility reasons it's allowed to suffix patterns with the `;` character. But it is not recommended to do that.

##### 7.8.3.2.2. Pattern binding

For referring to the matched object, use a pattern binding variable such as `$p`.

Example 7.58. Pattern with a binding variable

    rule ...
    when
        $p : Person()
    then
        System.out.println( "Person " + $p );
    end

The prefixed dollar symbol (`$`) is just a convention; it can be useful in complex rules where it helps to easily differentiate between variables and fields, but it is not mandatory.

#### 7.8.3.3. Constraint (part of a pattern)

##### 7.8.3.3.1. What is a constraint?

A constraint is an expression that returns `true` or `false`. This example has a constraint that states 5 is smaller than 6:

    Person( 5 < 6 )  // just an example, as constraints like this would be useless in a real pattern

In essence, it's a Java expression with some enhancements (such as property access) and a few differences (such as `equals()` semantics for `==`). Let's take a deeper look.

##### 7.8.3.3.2. Property access on Java Beans (POJO's)

Any bean property can be used directly. A bean property is exposed using a standard Java bean getter: a method `getMyProperty()` (or `isMyProperty()` for a primitive boolean) which takes no arguments and return something. For example: the age property is written as `age` in DRL instead of the getter `getAge()`:

    Person( age == 50 )

    // this is the same as:
    Person( getAge() == 50 )

Drools uses the standard JDK `Introspector` class to do this mapping, so it follows the standard Java bean specification.

## Note

We recommend using property access (`age`) over using getters explicitly (`getAge()`) because of performance enhancements through field indexing.

## Warning

Property accessors must not change the state of the object in a way that may effect the rules. Remember that the rule engine effectively caches the results of its matching in between invocations to make it faster.

    public int getAge() {
        age++; // Do NOT do this
        return age;
    }

    public int getAge() {
        Date now = DateUtil.now(); // Do NOT do this
        return DateUtil.differenceInYears(now, birthday);
    }

To solve this latter case, insert a fact that wraps the current date into working memory and update that fact between `fireAllRules` as needed.

## Note

The following fallback applies: if the getter of a property cannot be found, the compiler will resort to using the property name as a method name and without arguments:

    Person( age == 50 )

    // If Person.getAge() does not exists, this falls back to:
    Person( age() == 50 )

Nested property access is also supported:

    Person( address.houseNumber == 50 )

    // this is the same as:
    Person( getAddress().getHouseNumber() == 50 )

Nested properties are also indexed.

## Warning

In a stateful session, care should be taken when using nested accessors as the Working Memory is not aware of any of the nested values, and does not know when they change. Either consider them immutable while any of their parent references are inserted into the Working Memory. Or, instead, if you wish to modify a nested value you should mark all of the outer facts as updated. In the above example, when the `houseNumber` changes, any `Person` with that `Address` must be marked as updated.

##### 7.8.3.3.3. Java expression

You can use any Java expression that returns a `boolean` as a constraint inside the parentheses of a pattern. Java expressions can be mixed with other expression enhancements, such as property access:

    Person( age == 50 )

It is possible to change the evaluation priority by using parentheses, as in any logic or mathematical expression:

    Person( age > 100 && ( age % 10 == 0 ) )

It is possible to reuse Java methods:

    Person( Math.round( weight / ( height * height ) ) < 25.0 )

## Warning

As for property accessors, methods must not change the state of the object in a way that may affect the rules. Any method executed on a fact in the LHS should be a read only method.

    Person( incrementAndGetAge() == 10 ) // Do NOT do this

## Warning

The state of a fact should not change between rule invocations (unless those facts are marked as updated to the working memory on every change):

    Person( System.currentTimeMillis() % 1000 == 0 ) // Do NOT do this

Normal Java operator precedence applies, see the operator precedence list below.

## Important

All operators have normal Java semantics except for `==` and `!=`.

The `==` operator has null-safe `equals()` semantics:

    // Similar to: java.util.Objects.equals(person.getFirstName(), "John")
    // so (because "John" is not null) similar to:
    // "John".equals(person.getFirstName())
    Person( firstName == "John" )

The `!=` operator has null-safe `!equals()` semantics:

    // Similar to: !java.util.Objects.equals(person.getFirstName(), "John")
    Person( firstName != "John" )

Type coercion is always attempted if the field and the value are of different types; exceptions will be thrown if a bad coercion is attempted. For instance, if "ten" is provided as a string in a numeric evaluator, an exception is thrown, whereas "10" would coerce to a numeric 10. Coercion is always in favor of the field type and not the value type:

    Person( age == "10" ) // "10" is coerced to 10

##### 7.8.3.3.4. Comma separated AND

The comma character ('`,`') is used to separate constraint groups. It has implicit AND connective semantics.

    // Person is at least 50 and weighs at least 80 kg
    Person( age > 50, weight > 80 )

    // Person is at least 50, weighs at least 80 kg and is taller than 2 meter.
    Person( age > 50, weight > 80, height > 2 )

## Note

Although the `&&` and `,` operators have the same semantics, they are resolved with different priorities: The `&&` operator precedes the `||` operator. Both the `&&` and `||` operator precede the `,` operator. See the operator precedence list below.

The comma operator should be preferred at the top level constraint, as it makes constraints easier to read and the engine will often be able to optimize them better.

The comma (`,`) operator cannot be embedded in a composite constraint expression, such as parentheses:

    Person( ( age > 50, weight > 80 ) || height > 2 ) // Do NOT do this: compile error

    // Use this instead
    Person( ( age > 50 && weight > 80 ) || height > 2 )

##### 7.8.3.3.5. Binding variables

A property can be bound to a variable:

    // 2 persons of the same age
    Person( $firstAge : age ) // binding
    Person( age == $firstAge ) // constraint expression

The prefixed dollar symbol (`$`) is just a convention; it can be useful in complex rules where it helps to easily differentiate between variables and fields.

## Note

For backwards compatibility reasons, It's allowed (but not recommended) to mix a constraint binding and constraint expressions as such:

    // Not recommended
    Person( $age : age * 2 < 100 )

    // Recommended (separates bindings and constraint expressions)
    Person( age * 2 < 100, $age : age )

Bound variable restrictions using the operator `==` provide for very fast execution as it use hash indexing to improve performance.

##### 7.8.3.3.6. Unification

Drools does not allow bindings to the same declaration. However this is an important aspect to derivation query unification. While positional arguments are always processed with unification a special unification symbol, ':=', was introduced for named arguments named arguments. The following "unifies" the age argument across two people.

    Person( $age := age )
    Person( $age := age)

In essence unification will declare a binding for the first occurrence and constrain to the same value of the bound field for sequence occurrences.

##### 7.8.3.3.7. Grouped accessors for nested objects

Often it happens that it is necessary to access multiple properties of a nested object as in the following example

    Person( name == "mark", address.city == "london", address.country == "uk" )

These accessors to nested objects can be grouped with a '.(...)' syntax providing more readable rules as in

    Person( name==  "mark", address.( city == "london", country ==  "uk") )

Note the '.' prefix, this is necessary to differentiate the nested object constraints from a method call.

##### 7.8.3.3.8. Inline casts and coercion

When dealing with nested objects, it also quite common the need to cast to a subtype. It is possible to do that via the # symbol as in:

    Person( name=="mark", address#LongAddress.country == "uk" )

This example casts Address to LongAddress, making its getters available. If the cast is not possible (instanceof returns false), the evaluation will be considered false. Also fully qualified names are supported:

    Person( name=="mark", address#org.domain.LongAddress.country == "uk" )

It is possible to use multiple inline casts in the same expression:

    Person( name == "mark", address#LongAddress.country#DetailedCountry.population > 10000000 )

moreover, since we also support the instanceof operator, if that is used we will infer its results for further uses of that field, within that pattern:

    Person( name=="mark", address instanceof LongAddress, address.country == "uk" )

##### 7.8.3.3.9. Special literal support

Besides normal Java literals (including Java 5 enums), this literal is also supported:

###### 7.8.3.3.9.1. Date literal

The date format `dd-mmm-yyyy` is supported by default. You can customize this by providing an alternative date format mask as the System property named `drools.dateformat`. If more control is required, use a restriction.

Example 7.59. Date Literal Restriction

    Cheese( bestBefore < "27-Oct-2009" )

##### 7.8.3.3.10. List and Map access

It's possible to directly access a `List` value by index:

    // Same as childList(0).getAge() == 18
    Person( childList[0].age == 18 )

It's also possible to directly access a `Map` value by key:

    // Same as credentialMap.get("jsmith").isValid()
    Person( credentialMap["jsmith"].valid )

##### 7.8.3.3.11. Abbreviated combined relation condition

This allows you to place more than one restriction on a field using the restriction connectives `&&` or `||`. Grouping via parentheses is permitted, resulting in a recursive syntax pattern.

Figure 7.13. Abbreviated combined relation condition

Figure 7.14. Abbreviated combined relation condition with parentheses

    // Simple abbreviated combined relation condition using a single &&
    Person( age > 30 && < 40 )

    // Complex abbreviated combined relation using groupings
    Person( age ( (> 30 && < 40) ||
                  (> 20 && < 25) ) )

    // Mixing abbreviated combined relation with constraint connectives
    Person( age > 30 && < 40 || location == "london" )

##### 7.8.3.3.12. Special DRL operators

Figure 7.15. Operators

Coercion to the correct value for the evaluator and the field will be attempted.

###### 7.8.3.3.12.1. The operators `<` `<=` `>` `>=`

These operators can be used on properties with natural ordering. For example, for Date fields, `<` means before, for `String` fields, it means alphabetically lower.

    Person( firstName < $otherFirstName )

    Person( birthDate < $otherBirthDate )

Only applies on `Comparable` properties.

###### 7.8.3.3.12.2. Null-safe dereferencing operator

The !. operator allows to derefencing in a null-safe way. More in details the matching algorithm requires the value to the left of the !. operator to be not null in order to give a positive result for pattern matching itself. In other words the pattern:

    Person( $streetName : address!.street )

will be internally translated in:

    Person( address != null, $streetName : address.street )

###### 7.8.3.3.12.3. The operator `matches`

Matches a field against any valid Java Regular Expression. Typically that regexp is a string literal, but variables that resolve to a valid regexp are also allowed.

Example 7.60. Regular Expression Constraint

    Cheese( type matches "(Buffalo)?\\S*Mozarella" )

## Note

Like in Java, regular expressions written as string literals need to escape '`\`'.

Only applies on `String` properties. Using `matches` against a `null` value always evaluates to false.

###### 7.8.3.3.12.4. The operator `not matches`

The operator returns true if the String does not match the regular expression. The same rules apply as for the `matches` operator. Example:

Example 7.61. Regular Expression Constraint

    Cheese( type not matches "(Buffulo)?\\S*Mozarella" )

Only applies on `String` properties. Using `not matches` against a `null` value always evaluates to true.

###### 7.8.3.3.12.5. The operator `contains`

The operator `contains` is used to check whether a field that is a Collection or elements contains the specified value.

Example 7.62. Contains with Collections

    CheeseCounter( cheeses contains "stilton" ) // contains with a String literal
    CheeseCounter( cheeses contains $var ) // contains with a variable

Only applies on `Collection` properties.

###### 7.8.3.3.12.6. The operator `not contains`

The operator `not contains` is used to check whether a field that is a Collection or elements does not contain the specified value.

Example 7.63. Literal Constraint with Collections

    CheeseCounter( cheeses not contains "cheddar" ) // not contains with a String literal
    CheeseCounter( cheeses not contains $var ) // not contains with a variable

Only applies on `Collection` properties.

> ## Note

> For backward compatibility, the `excludes` operator is supported as a synonym for `not contains`.

###### 7.8.3.3.12.7. The operator `memberOf`

The operator `memberOf` is used to check whether a field is a member of a collection or elements; that collection must be a variable.

Example 7.64. Literal Constraint with Collections

    CheeseCounter( cheese memberOf $matureCheeses )

###### 7.8.3.3.12.8. The operator `not memberOf`

The operator `not memberOf` is used to check whether a field is not a member of a collection or elements; that collection must be a variable.

Example 7.65. Literal Constraint with Collections

    CheeseCounter( cheese not memberOf $matureCheeses )

###### 7.8.3.3.12.9. The operator `soundslike`

This operator is similar to `matches`, but it checks whether a word has almost the same sound (using English pronunciation) as the given value. This is based on the Soundex algorithm (see `http://en.wikipedia.org/wiki/Soundex`).

Example 7.66. Test with soundslike

    // match cheese "fubar" or "foobar"
    Cheese( name soundslike 'foobar' )

###### 7.8.3.3.12.10. The operator `str`

This operator `str` is used to check whether a field that is a `String` starts with or ends with a certain value. It can also be used to check the length of the String.

    Message( routingValue str[startsWith] "R1" )

    Message( routingValue str[endsWith] "R2" )

    Message( routingValue str[length] 17 )

###### 7.8.3.3.12.11. The operators `in` and `not in` (compound value restriction)

The compound value restriction is used where there is more than one possible value to match. Currently only the `in` and `not in` evaluators support this. The second operand of this operator must be a comma-separated list of values, enclosed in parentheses. Values may be given as variables, literals, return values or qualified identifiers. Both evaluators are actually syntactic sugar, internally rewritten as a list of multiple restrictions using the operators `!=` and `==`.

Figure 7.16. compoundValueRestriction

Example 7.67. Compound Restriction using "in"

    Person( $cheese : favouriteCheese )
    Cheese( type in ( "stilton", "cheddar", $cheese ) )

##### 7.8.3.3.13. Inline eval operator (deprecated)

Figure 7.17. Inline Eval Expression

An inline eval constraint can use any valid dialect expression as long as it results to a primitive boolean. The expression must be constant over time. Any previously bound variable, from the current or previous pattern, can be used; autovivification is also used to auto-create field binding variables. When an identifier is found that is not a current variable, the builder looks to see if the identifier is a field on the current object type, if it is, the field binding is auto-created as a variable of the same name. This is called autovivification of field variables inside of inline eval's.

This example will find all male-female pairs where the male is 2 years older than the female; the variable `age` is auto-created in the second pattern by the autovivification process.

Example 7.68. Return Value operator

    Person( girlAge : age, sex = "F" )
    Person( eval( age == girlAge + 2 ), sex = 'M' ) // eval() is actually obsolete in this example

## Note

Inline eval's are effectively obsolete as their inner syntax is now directly supported. It's recommended not to use them. Simply write the expression without wrapping eval() around it.

##### 7.8.3.3.14. Operator precedence

The operators are evaluated in this precedence:

Table 7.1. Operator precedence

Operator type | Operators | Notes
--- | --- | ---
(nested / null safe) property access | `.` `!.` | Not normal Java semantics
List/Map access | `[ ]` | Not normal Java semantics
constraint binding | `:` | Not normal Java semantics
multiplicative | `*` `/` `%` |
additive | `+` `-` |
shift | `<<` `>>` `>>>` |
relational | `<` `>` `<=` `>=` `instanceof` |
equality | `==` `!=` | Does not use normal Java (not) same semantics: uses (not) equals semantics instead.
non-short circuiting AND | `&` |
non-short circuiting exclusive OR | `^` |
non-short circuiting inclusive OR | `|` |
logical AND | `&&` |
logical OR | `||` |
ternary | `? :` |
Comma separated AND | `,` | Not normal Java semantics

#### 7.8.3.4. Positional Arguments

Patterns now support positional arguments on type declarations.

Positional arguments are ones where you don't need to specify the field name, as the position maps to a known named field. i.e. Person( name == "mark" ) can be rewritten as Person( "mark"; ). The semicolon ';' is important so that the engine knows that everything before it is a positional argument. Otherwise we might assume it was a boolean expression, which is how it could be interpreted after the semicolon. You can mix positional and named arguments on a pattern by using the semicolon ';' to separate them. Any variables used in a positional that have not yet been bound will be bound to the field that maps to that position.

    declare Cheese
        name : String
        shop : String
        price : int
    end

Example patterns, with two constraints and a binding. Remember semicolon ';' is used to differentiate the positional section from the named argument section. Variables and literals and expressions using just literals are supported in positional arguments, but not variables. Positional arguments are always resolved using unification.

    Cheese( "stilton", "Cheese Shop", p; )
    Cheese( "stilton", "Cheese Shop"; p : price )
    Cheese( "stilton"; shop == "Cheese Shop", p : price )
    Cheese( name == "stilton"; shop == "Cheese Shop", p : price )

Positional arguments that are given a previously declared binding will constrain against that using unification; these are referred to as input arguments. If the binding does not yet exist, it will create the declaration binding it to the field represented by the position argument; these are referred to as output arguments.

#### 7.8.3.5. Fine grained property change listeners

When you call modify() (see the modify statement section) on a given object it will trigger a revaluation of all patterns of the matching object type in the knowledge base. This can can lead to unwanted and useless evaluations and in the worst cases to infinite recursions. The only workaround to avoid it was to split up your objects into smaller ones having a 1 to 1 relationship with the original object.

This feature allows the pattern matching to only react to modification of properties actually constrained or bound inside of a given pattern. That will help with performance and recursion and avoid artificial object splitting.

By default this feature is off in order to make the behavior of the rule engine backward compatible with the former releases. When you want to activate it on a specific bean you have to annotate it with @propertyReactive. This annotation works both on DRL type declarations:

    declare Person
    @propertyReactive
        firstName : String
        lastName : String
    end

and on Java classes:

    @PropertyReactive
        public static class Person {
        private String firstName;
        private String lastName;
    }

In this way, for instance, if you have a rule like the following:

    rule "Every person named Mario is a male" when
        $person : Person( firstName == "Mario" )
    then
        modify ( $person )  { setMale( true ) }
    end

you won't have to add the no-loop attribute to it in order to avoid an infinite recursion because the engine recognizes that the pattern matching is done on the 'firstName' property while the RHS of the rule modifies the 'male' one. Note that this feature does not work for update(), and this is one of the reasons why we promote modify() since it encapsulates the field changes within the statement. Moreover, on Java classes, you can also annotate any method to say that its invocation actually modifies other properties. For instance in the former Person class you could have a method like:

    @Modifies( { "firstName", "lastName" } )
    public void setName(String name) {
        String[] names = name.split("\\s");
        this.firstName = names[0];
        this.lastName = names[1];
    }

That means that if a rule has a RHS like the following:

    modify($person) { setName("Mario Fusco") }

it will correctly recognize that the values of both properties 'firstName' and 'lastName' could have potentially been modified and act accordingly, not missing of reevaluating the patterns constrained on them. At the moment the usage of @Modifies is not allowed on fields but only on methods. This is coherent with the most common scenario where the @Modifies will be used for methods that are not related with a class field as in the Person.setName() in the former example. Also note that @Modifies is not transitive, meaning that if another method internally invokes the Person.setName() one it won't be enough to annotate it with @Modifies( { "name" } ), but it is necessary to use @Modifies( { "firstName", "lastName" } ) even on it. Very likely @Modifies transitivity will be implemented in the next release.

For what regards nested accessors, the engine will be notified only for top level fields. In other words a pattern matching like:

    Person ( address.city.name == "London )

will be revaluated only for modification of the 'address' property of a Person object. In the same way the constraints analysis is currently strictly limited to what there is inside a pattern. Another example could help to clarify this. An LHS like the following:

    $p : Person( )
    Car( owner = $p.name )

will not listen on modifications of the person's name, while this one will do:

    Person( $name : name )
    Car( owner = $name )

To overcome this problem it is possible to annotate a pattern with @watch as it follows:

    $p : Person( ) @watch ( name )
    Car( owner = $p.name )

Indeed, annotating a pattern with @watch allows you to modify the inferred set of properties for which that pattern will react. Note that the properties named in the @watch annotation are actually added to the ones automatically inferred, but it is also possible to explicitly exclude one or more of them prepending their name with a ! and to make the pattern to listen for all or none of the properties of the type used in the pattern respectively with the wildcrds * and !*. So, for example, you can annotate a pattern in the LHS of a rule like:

    // listens for changes on both firstName (inferred) and lastName
    Person( firstName == $expectedFirstName ) @watch( lastName )

    // listens for all the properties of the Person bean
    Person( firstName == $expectedFirstName ) @watch( * )

    // listens for changes on lastName and explicitly exclude firstName
    Person( firstName == $expectedFirstName ) @watch( lastName, !firstName )

    // listens for changes on all the properties except the age one
    Person( firstName == $expectedFirstName ) @watch( *, !age )

Since doesn't make sense to use this annotation on a pattern using a type not annotated with @PropertyReactive the rule compiler will raise a compilation error if you try to do so. Also the duplicated usage of the same property in @watch (for example like in: @watch( firstName, ! firstName ) ) will end up in a compilation error. In a next release we will make the automatic detection of the properties to be listened smarter by doing analysis even outside of the pattern.

It also possible to enable this feature by default on all the types of your model or to completely disallow it by using on option of the KnowledgeBuilderConfiguration. In particular this new PropertySpecificOption can have one of the following 3 values:

    - DISABLED => the feature is turned off and all the other related annotations are just ignored
    - ALLOWED => this is the default behavior: types are not property reactive unless they are not annotated with @PropertySpecific
    - ALWAYS => all types are property reactive by default

So, for example, to have a KnowledgeBuilder generating property reactive types by default you could do:

    KnowledgeBuilderConfiguration config = KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration();
    config.setOption(PropertySpecificOption.ALWAYS);
    KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(config);

In this last case it will be possible to disable the property reactivity feature on a specific type by annotating it with @ClassReactive.

#### 7.8.3.6. Basic conditional elements

##### 7.8.3.6.1. Conditional Element `and`

The Conditional Element `"and"` is used to group other Conditional Elements into a logical conjunction. Drools supports both prefix `and` and infix `and`.

Figure 7.18. infixAnd

Traditional infix `and` is supported:

    //infixAnd
    Cheese( cheeseType : type ) and Person( favouriteCheese == cheeseType )

Explicit grouping with parentheses is also supported:

    //infixAnd with grouping
    ( Cheese( cheeseType : type ) and
      ( Person( favouriteCheese == cheeseType ) or
        Person( favouriteCheese == cheeseType ) )

## Note

The symbol `&&` (as an alternative to `and`) is deprecated. But it is still supported in the syntax for backwards compatibility.

Figure 7.19. prefixAnd

Prefix `and` is also supported:

    (and Cheese( cheeseType : type )
         Person( favouriteCheese == cheeseType ) )

The root element of the LHS is an implicit prefix `and` and doesn't need to be specified:

Example 7.69. implicit root prefixAnd

    when
        Cheese( cheeseType : type )
        Person( favouriteCheese == cheeseType )
    then
        ...

##### 7.8.3.6.2. Conditional Element `or`

The Conditional Element `or` is used to group other Conditional Elements into a logical disjunction. Drools supports both prefix `or` and infix `or`.

Figure 7.20. infixOr

Traditional infix `or` is supported:

    //infixOr
    Cheese( cheeseType : type ) or Person( favouriteCheese == cheeseType )

Explicit grouping with parentheses is also supported:

    //infixOr with grouping
    ( Cheese( cheeseType : type ) or
      ( Person( favouriteCheese == cheeseType ) and
        Person( favouriteCheese == cheeseType ) )

## Note

The symbol `||` (as an alternative to `or`) is deprecated. But it is still supported in the syntax for backwards compatibility.

Figure 7.21. prefixOr

Prefix `or` is also supported:

    (or Person( sex == "f", age > 60 )
        Person( sex == "m", age > 65 )

## Note

The behavior of the Conditional Element `or` is different from the connective `||` for constraints and restrictions in field constraints. The engine actually has no understanding of the Conditional Element `or`. Instead, via a number of different logic transformations, a rule with `or` is rewritten as a number of subrules. This process ultimately results in a rule that has a single `or` as the root node and one subrule for each of its CEs. Each subrule can activate and fire like any normal rule; there is no special behavior or interaction between these subrules. - This can be most confusing to new rule authors.

The Conditional Element `or` also allows for optional pattern binding. This means that each resulting subrule will bind its pattern to the pattern binding. Each pattern must be bound separately, using eponymous variables:

    pensioner : ( Person( sex == "f", age > 60 ) or Person( sex == "m", age > 65 ) )

    (or pensioner : Person( sex == "f", age > 60 )
        pensioner : Person( sex == "m", age > 65 ) )

Since the conditional element `or` results in multiple subrule generation, one for each possible logically outcome, the example above would result in the internal generation of two rules. These two rules work independently within the Working Memory, which means both can match, activate and fire - there is no shortcutting.

The best way to think of the conditional element `or` is as a shortcut for generating two or more similar rules. When you think of it that way, it's clear that for a single rule there could be multiple activations if two or more terms of the disjunction are true.

##### 7.8.3.6.3. Conditional Element `not`

Figure 7.22. not

The CE `not` is first order logic's non-existential quantifier and checks for the non-existence of something in the Working Memory. Think of "not" as meaning "there must be none of...".

The keyword `not` may be followed by parentheses around the CEs that it applies to. In the simplest case of a single pattern (like below) you may optionally omit the parentheses.

Example 7.70. No Busses

    not Bus()

Example 7.71. No red Busses

    // Brackets are optional:
    not Bus(color == "red")
    // Brackets are optional:
    not ( Bus(color == "red", number == 42) )
    // "not" with nested infix and - two patterns,
    // brackets are requires:
    not ( Bus(color == "red") and
          Bus(color == "blue") )

##### 7.8.3.6.4. Conditional Element `exists`

Figure 7.23. exists

The CE `exists` is first order logic's existential quantifier and checks for the existence of something in the Working Memory. Think of "exists" as meaning "there is at least one..". It is different from just having the pattern on its own, which is more like saying "for each one of...". If you use `exists` with a pattern, the rule will only activate at most once, regardless of how much data there is in working memory that matches the condition inside of the `exists` pattern. Since only the existence matters, no bindings will be established.

The keyword `exists` must be followed by parentheses around the CEs that it applies to. In the simplest case of a single pattern (like below) you may omit the parentheses.

Example 7.72. At least one Bus

    exists Bus()

Example 7.73. At least one red Bus

    exists Bus(color == "red")
    // brackets are optional:
    exists ( Bus(color == "red", number == 42) )
    // "exists" with nested infix and,
    // brackets are required:
    exists ( Bus(color == "red") and
             Bus(color == "blue") )

#### 7.8.3.7. Advanced conditional elements

##### 7.8.3.7.1. Conditional Element `forall`

Figure 7.24. forall

The Conditional Element `forall` completes the First Order Logic support in Drools. The Conditional Element `forall` evaluates to true when all facts that match the first pattern match all the remaining patterns. Example:

    rule "All English buses are red"
    when
        forall( $bus : Bus( type == 'english')
                       Bus( this == $bus, color = 'red' ) )
    then
        // all English buses are red
    end

In the above rule, we "select" all Bus objects whose type is "english". Then, for each fact that matches this pattern we evaluate the following patterns and if they match, the forall CE will evaluate to true.

To state that all facts of a given type in the working memory must match a set of constraints, `forall` can be written with a single pattern for simplicity. Example:

Example 7.74. Single Pattern Forall

    rule "All Buses are Red"
    when
        forall( Bus( color == 'red' ) )
    then
        // all Bus facts are red
    end

Another example shows multiple patterns inside the `forall`:

Example 7.75. Multi-Pattern Forall

    rule "all employees have health and dental care programs"
    when
        forall( $emp : Employee()
                HealthCare( employee == $emp )
                DentalCare( employee == $emp )
              )
    then
        // all employees have health and dental care
    end

Forall can be nested inside other CEs. For instance, `forall` can be used inside a `not` CE. Note that only single patterns have optional parentheses, so that with a nested `forall` parentheses must be used:

Example 7.76. Combining Forall with Not CE

    rule "not all employees have health and dental care"
    when
        not ( forall( $emp : Employee()
                      HealthCare( employee == $emp )
                      DentalCare( employee == $emp ) )
            )
    then
        // not all employees have health and dental care
    end

As a side note, `forall( p1 p2 p3...)` is equivalent to writing:

    not(p1 and not(and p2 p3...))

Also, it is important to note that `forall` is a scope delimiter. Therefore, it can use any previously bound variable, but no variable bound inside it will be available for use outside of it.

##### 7.8.3.7.2. Conditional Element `from`

Figure 7.25. from

The Conditional Element `from` enables users to specify an arbitrary source for data to be matched by LHS patterns. This allows the engine to reason over data not in the Working Memory. The data source could be a sub-field on a bound variable or the results of a method call. It is a powerful construction that allows out of the box integration with other application components and frameworks. One common example is the integration with data retrieved on-demand from databases using hibernate named queries.

The expression used to define the object source is any expression that follows regular MVEL syntax. Therefore, it allows you to easily use object property navigation, execute method calls and access maps and collections elements.

Here is a simple example of reasoning and binding on another pattern sub-field:

    rule "validate zipcode"
    when
        Person( $personAddress : address )
        Address( zipcode == "23920W") from $personAddress
    then
        // zip code is ok
    end

With all the flexibility from the new expressiveness in the Drools engine you can slice and dice this problem many ways. This is the same but shows how you can use a graph notation with the 'from':

    rule "validate zipcode"
    when
        $p : Person( )
        $a : Address( zipcode == "23920W") from $p.address
    then
        // zip code is ok
    end

Previous examples were evaluations using a single pattern. The CE `from` also support object sources that return a collection of objects. In that case, `from` will iterate over all objects in the collection and try to match each of them individually. For instance, if we want a rule that applies 10% discount to each item in an order, we could do:

    rule "apply 10% discount to all items over US$ 100,00 in an order"
    when
        $order : Order()
        $item  : OrderItem( value > 100 ) from $order.items
    then
        // apply discount to $item
    end

The above example will cause the rule to fire once for each item whose value is greater than 100 for each given order.

You must take caution, however, when using `from`, especially in conjunction with the `lock-on-active` rule attribute as it may produce unexpected results. Consider the example provided earlier, but now slightly modified as follows:

    rule "Assign people in North Carolina (NC) to sales region 1"
    ruleflow-group "test"
    lock-on-active true
    when
        $p : Person( )
        $a : Address( state == "NC") from $p.address
    then
        modify ($p) {} // Assign person to sales region 1 in a modify block
    end

    rule "Apply a discount to people in the city of Raleigh"
    ruleflow-group "test"
    lock-on-active true
    when
        $p : Person( )
        $a : Address( city == "Raleigh") from $p.address
    then
        modify ($p) {} // Apply discount to person in a modify block
    end

In the above example, persons in Raleigh, NC should be assigned to sales region 1 and receive a discount; i.e., you would expect both rules to activate and fire. Instead you will find that only the second rule fires.

If you were to turn on the audit log, you would also see that when the second rule fires, it deactivates the first rule. Since the rule attribute `lock-on-active` prevents a rule from creating new activations when a set of facts change, the first rule fails to reactivate. Though the set of facts have not changed, the use of `from` returns a new fact for all intents and purposes each time it is evaluated.

First, it's important to review why you would use the above pattern. You may have many rules across different rule-flow groups. When rules modify working memory and other rules downstream of your RuleFlow (in different rule-flow groups) need to be reevaluated, the use of `modify` is critical. You don't, however, want other rules in the same rule-flow group to place activations on one another recursively. In this case, the `no-loop` attribute is ineffective, as it would only prevent a rule from activating itself recursively. Hence, you resort to `lock-on-active`.

There are several ways to address this issue:

- Avoid the use of `from` when you can assert all facts into working memory or use nested object references in your constraint expressions (shown below).

- Place the variable assigned used in the modify block as the last sentence in your condition (LHS).

- Avoid the use of `lock-on-active` when you can explicitly manage how rules within the same rule-flow group place activations on one another (explained below).

The preferred solution is to minimize use of `from` when you can assert all your facts into working memory directly. In the example above, both the Person and Address instance can be asserted into working memory. In this case, because the graph is fairly simple, an even easier solution is to modify your rules as follows:

    rule "Assign people in North Carolina (NC) to sales region 1"
    ruleflow-group "test"
    lock-on-active true
    when
        $p : Person(address.state == "NC" )
    then
        modify ($p) {} // Assign person to sales region 1 in a modify block
    end

    rule "Apply a discount to people in the city of Raleigh"
    ruleflow-group "test"
    lock-on-active true
    when
        $p : Person(address.city == "Raleigh" )
    then
        modify ($p) {} //Apply discount to person in a modify block
    end

Now, you will find that both rules fire as expected. However, it is not always possible to access nested facts as above. Consider an example where a Person holds one or more Addresses and you wish to use an existential quantifier to match people with at least one address that meets certain conditions. In this case, you would have to resort to the use of `from` to reason over the collection.

There are several ways to use `from` to achieve this and not all of them exhibit an issue with the use of `lock-on-active`. For example, the following use of `from` causes both rules to fire as expected:

    rule "Assign people in North Carolina (NC) to sales region 1"
    ruleflow-group "test"
    lock-on-active true
    when
        $p : Person($addresses : addresses)
        exists (Address(state == "NC") from $addresses)
    then
        modify ($p) {} // Assign person to sales region 1 in a modify block
    end

    rule "Apply a discount to people in the city of Raleigh"
    ruleflow-group "test"
    lock-on-active true
    when
        $p : Person($addresses : addresses)
        exists (Address(city == "Raleigh") from $addresses)
    then
        modify ($p) {} // Apply discount to person in a modify block
    end

However, the following slightly different approach does exhibit the problem:

    rule "Assign people in North Carolina (NC) to sales region 1"
    ruleflow-group "test"
    lock-on-active true
    when
        $assessment : Assessment()
        $p : Person()
        $addresses : List() from $p.addresses
        exists (Address( state == "NC") from $addresses)
    then
        modify ($assessment) {} // Modify assessment in a modify block
    end

    rule "Apply a discount to people in the city of Raleigh"
    ruleflow-group "test"
    lock-on-active true
    when
        $assessment : Assessment()
        $p : Person()
        $addresses : List() from $p.addresses
        exists (Address( city == "Raleigh") from $addresses)
    then
        modify ($assessment) {} // Modify assessment in a modify block
    end

In the above example, the $addresses variable is returned from the use of `from`. The example also introduces a new object, assessment, to highlight one possible solution in this case. If the $assessment variable assigned in the condition (LHS) is moved to the last condition in each rule, both rules fire as expected.

Though the above examples demonstrate how to combine the use of `from` with `lock-on-active` where no loss of rule activations occurs, they carry the drawback of placing a dependency on the order of conditions on the LHS. In addition, the solutions present greater complexity for the rule author in terms of keeping track of which conditions may create issues.

A better alternative is to assert more facts into working memory. In this case, a person's addresses may be asserted into working memory and the use of `from` would not be necessary.

There are cases, however, where asserting all data into working memory is not practical and we need to find other solutions. Another option is to reevaluate the need for `lock-on-active`. An alternative to `lock-on-active` is to directly manage how rules within the same rule-flow group activate one another by including conditions in each rule that prevent rules from activating each other recursively when working memory is modified. For example, in the case above where a discount is applied to citizens of Raleigh, a condition may be added to the rule that checks whether the discount has already been applied. If so, the rule does not activate.

##### 7.8.3.7.3. Conditional Element `collect`

Figure 7.26. collect

The Conditional Element `collect` allows rules to reason over a collection of objects obtained from the given source or from the working memory. In First Oder Logic terms this is the cardinality quantifier. A simple example:

    import java.util.ArrayList

    rule "Raise priority if system has more than 3 pending alarms"
    when
        $system : System()
        $alarms : ArrayList( size >= 3 )
                  from collect( Alarm( system == $system, status == 'pending' ) )
    then
        // Raise priority, because system $system has
        // 3 or more alarms pending. The pending alarms
        // are $alarms.
    end

In the above example, the rule will look for all pending alarms in the working memory for each given system and group them in ArrayLists. If 3 or more alarms are found for a given system, the rule will fire.

The result pattern of `collect` can be any concrete class that implements the `java.util.Collection` interface and provides a default no-arg public constructor. This means that you can use Java collections like ArrayList, LinkedList, HashSet, etc., or your own class, as long as it implements the `java.util.Collection` interface and provide a default no-arg public constructor.

Both source and result patterns can be constrained as any other pattern.

Variables bound before the `collect` CE are in the scope of both source and result patterns and therefore you can use them to constrain both your source and result patterns. But note that `collect` is a scope delimiter for bindings, so that any binding made inside of it is not available for use outside of it.

Collect accepts nested `from` CEs. The following example is a valid use of "collect":

    import java.util.LinkedList;

    rule "Send a message to all mothers"
    when
        $town : Town( name == 'Paris' )
        $mothers : LinkedList()
                   from collect( Person( gender == 'F', children > 0 )
                                 from $town.getPeople()
                               )
    then
        // send a message to all mothers
    end

##### 7.8.3.7.4. Conditional Element `accumulate`

Figure 7.27. accumulate

The Conditional Element `accumulate` is a more flexible and powerful form of `collect`, in the sense that it can be used to do what `collect` does and also achieve results that the CE `collect` is not capable of achieving. Accumulate allows a rule to iterate over a collection of objects, executing custom actions for each of the elements, and at the end, it returns a result object.

Accumulate supports both the use of pre-defined accumulate functions, or the use of inline custom code. Inline custom code should be avoided though, as it is harder for rule authors to maintain, and frequently leads to code duplication. Accumulate functions are easier to test and reuse.

The Accumulate CE also supports multiple different syntaxes. The preferred syntax is the top level accumulate, as noted bellow, but all other syntaxes are supported for backward compatibility.

###### 7.8.3.7.4.1. Accumulate CE (preferred syntax)

The top level accumulate syntax is the most compact and flexible syntax. The simplified syntax is as follows:

    accumulate( <source pattern>; <functions> [;<constraints>] )

For instance, a rule to calculate the minimum, maximum and average temperature reading for a given sensor and that raises an alarm if the minimum temperature is under 20C degrees and the average is over 70C degrees could be written in the following way, using Accumulate:

## Note

The DRL language defines "`acc`" as a synonym of "`accumulate`". The author might prefer to use "`acc`" as a less verbose keyword or the full keyword "`accumulate`" for legibility.

    rule "Raise alarm"
    when
        $s : Sensor()
        accumulate( Reading( sensor == $s, $temp : temperature );
                    $min : min( $temp ),
                    $max : max( $temp ),
                    $avg : average( $temp );
                    $min < 20, $avg > 70 )
    then
        // raise the alarm
    end

In the above example, min, max and average are Accumulate Functions and will calculate the minimum, maximum and average temperature values over all the readings for each sensor.

Drools ships with several built-in accumulate functions, including:

- average

- min

- max

- count

- sum

- collectList

- collectSet

These common functions accept any expression as input. For instance, if someone wants to calculate the average profit on all items of an order, a rule could be written using the average function:

    rule "Average profit"
    when
        $order : Order()
        accumulate( OrderItem( order == $order, $cost : cost, $price : price );
                    $avgProfit : average( 1 - $cost / $price ) )
    then
        // average profit for $order is $avgProfit
    end

Accumulate Functions are all pluggable. That means that if needed, custom, domain specific functions can easily be added to the engine and rules can start to use them without any restrictions. To implement a new Accumulate Function all one needs to do is to create a Java class that implements the `org.drools.core.runtime.rule.TypedAccumulateFunction` interface. As an example of an Accumulate Function implementation, the following is the implementation of the `average` function:

    /**
     * An implementation of an accumulator capable of calculating average values
     */
    public class AverageAccumulateFunction implements org.drools.core.runtime.rule.TypedAccumulateFunction {

        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {

        }

        public void writeExternal(ObjectOutput out) throws IOException {

        }

        public static class AverageData implements Externalizable {
            public int    count = 0;
            public double total = 0;

            public AverageData() {}

            public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
                count   = in.readInt();
                total   = in.readDouble();
            }

            public void writeExternal(ObjectOutput out) throws IOException {
                out.writeInt(count);
                out.writeDouble(total);
            }

        }

        /* (non-Javadoc)
         * @see org.drools.base.accumulators.AccumulateFunction#createContext()
         */
        public Serializable createContext() {
            return new AverageData();
        }

        /* (non-Javadoc)
         * @see org.drools.core.base.accumulators.AccumulateFunction#init(java.lang.Object)
         */
        public void init(Serializable context) throws Exception {
            AverageData data = (AverageData) context;
            data.count = 0;
            data.total = 0;
        }

        /* (non-Javadoc)
         * @see org.drools.core.base.accumulators.AccumulateFunction#accumulate(java.lang.Object, java.lang.Object)
         */
        public void accumulate(Serializable context,
                               Object value) {
            AverageData data = (AverageData) context;
            data.count++;
            data.total += ((Number) value).doubleValue();
        }

        /* (non-Javadoc)
         * @see org.drools.core.base.accumulators.AccumulateFunction#reverse(java.lang.Object, java.lang.Object)
         */
        public void reverse(Serializable context,
                            Object value) throws Exception {
            AverageData data = (AverageData) context;
            data.count--;
            data.total -= ((Number) value).doubleValue();
        }

        /* (non-Javadoc)
         * @see org.drools.core.base.accumulators.AccumulateFunction#getResult(java.lang.Object)
         */
        public Object getResult(Serializable context) throws Exception {
            AverageData data = (AverageData) context;
            return new Double( data.count == 0 ? 0 : data.total / data.count );
        }

        /* (non-Javadoc)
         * @see org.drools.core.base.accumulators.AccumulateFunction#supportsReverse()
         */
        public boolean supportsReverse() {
            return true;
        }

        /**
         * {@inheritDoc}
         */
        public Class< ? > getResultType() {
            return Number.class;
        }

    }

The code for the function is very simple, as we could expect, as all the "dirty" integration work is done by the engine. Finally, to use the function in the rules, the author can import it using the "import accumulate" statement:

    import accumulate <class_name> <function_name>

For instance, if one implements the class `some.package.VarianceFunction` function that implements the `variance` function and wants to use it in the rules, he would do the following:

Example 7.77. Example of importing and using the custom "`variance`" accumulate function

    import accumulate some.package.VarianceFunction variance

    rule "Calculate Variance"
    when
        accumulate( Test( $s : score ), $v : variance( $s ) )
    then
        // the variance of the test scores is $v
    end

## Note

The built in functions (sum, average, etc) are imported automatically by the engine. Only user-defined custom accumulate functions need to be explicitly imported.

## Note

For backward compatibility, Drools still supports the configuration of accumulate functions through configuration files and system properties, but this is a deprecated method. In order to configure the variance function from the previous example using the configuration file or system property, the user would set a property like this:

    drools.accumulate.function.variance = some.package.VarianceFunction

Please note that "`drools.accumulate.function.`" is a prefix that must always be used, "`variance`" is how the function will be used in the drl files, and "`some.package.VarianceFunction`" is the fully qualified name of the class that implements the function behavior.

###### 7.8.3.7.4.2. Alternate Syntax: single function with return type

The accumulate syntax evolved over time with the goal of becoming more compact and expressive. Nevertheless, Drools still supports previous syntaxes for backward compatibility purposes.

In case the rule is using a single accumulate function on a given accumulate, the author may add a pattern for the result object and use the "from" keyword to link it to the accumulate result. Example: a rule to apply a 10% discount on orders over $100 could be written in the following way:

    rule "Apply 10% discount to orders over US$ 100,00"
    when
        $order : Order()
        $total : Number( doubleValue > 100 )
                 from accumulate( OrderItem( order == $order, $value : value ),
                                  sum( $value ) )
    then
        # apply discount to $order
    end

In the above example, the accumulate element is using only one function (sum), and so, the rules author opted to explicitly write a pattern for the result type of the accumulate function (Number) and write the constraints inside it. There are no problems in using this syntax over the compact syntax presented before, except that is is a bit more verbose. Also note that it is not allowed to use both the return type and the functions binding in the same accumulate statement.

###### 7.8.3.7.4.3. Accumulate with inline custom code

## Warning

The use of accumulate with inline custom code is not a good practice for several reasons, including difficulties on maintaining and testing rules that use them, as well as the inability of reusing that code. Implementing your own accumulate functions is very simple and straightforward, they are easy to unit test and to use. This form of accumulate is supported for backward compatibility only.

Another possible syntax for the accumulate is to define inline custom code, instead of using accumulate functions. As noted on the previous warned, this is discouraged though for the stated reasons.

The general syntax of the `accumulate` CE with inline custom code is:

    <result pattern> from accumulate( <source pattern>,
                                      init( <init code> ),
                                      action( <action code> ),
                                      reverse( <reverse code> ),
                                      result( <result expression> ) )

The meaning of each of the elements is the following:

- <source pattern>: the source pattern is a regular pattern that the engine will try to match against each of the source objects.

- <init code>: this is a semantic block of code in the selected dialect that will be executed once for each tuple, before iterating over the source objects.

- <action code>: this is a semantic block of code in the selected dialect that will be executed for each of the source objects.

- <reverse code>: this is an optional semantic block of code in the selected dialect that if present will be executed for each source object that no longer matches the source pattern. The objective of this code block is to undo any calculation done in the <action code> block, so that the engine can do decremental calculation when a source object is modified or deleted, hugely improving performance of these operations.

- <result expression>: this is a semantic expression in the selected dialect that is executed after all source objects are iterated.

- <result pattern>: this is a regular pattern that the engine tries to match against the object returned from the <result expression>. If it matches, the `accumulate` conditional element evaluates to true and the engine proceeds with the evaluation of the next CE in the rule. If it does not matches, the `accumulate` CE evaluates to false and the engine stops evaluating CEs for that rule.

It is easier to understand if we look at an example:

    rule "Apply 10% discount to orders over US$ 100,00"
    when
        $order : Order()
        $total : Number( doubleValue > 100 )
                 from accumulate( OrderItem( order == $order, $value : value ),
                                  init( double total = 0; ),
                                  action( total += $value; ),
                                  reverse( total -= $value; ),
                                  result( total ) )
    then
        # apply discount to $order
    end

In the above example, for each `Order` in the Working Memory, the engine will execute the init code initializing the total variable to zero. Then it will iterate over all `OrderItem` objects for that order, executing the action for each one (in the example, it will sum the value of all items into the total variable). After iterating over all `OrderItem` objects, it will return the value corresponding to the result expression (in the above example, the value of variable `total`). Finally, the engine will try to match the result with the `Number` pattern, and if the double value is greater than 100, the rule will fire.

The example used Java as the semantic dialect, and as such, note that the usage of the semicolon as statement delimiter is mandatory in the init, action and reverse code blocks. The result is an expression and, as such, it does not admit ';'. If the user uses any other dialect, he must comply to that dialect's specific syntax.

As mentioned before, the reverse code is optional, but it is strongly recommended that the user writes it in order to benefit from the improved performance on update and delete.

The `accumulate` CE can be used to execute any action on source objects. The following example instantiates and populates a custom object:

    rule "Accumulate using custom objects"
    when
        $person   : Person( $likes : likes )
        $cheesery : Cheesery( totalAmount > 100 )
                    from accumulate( $cheese : Cheese( type == $likes ),
                                     init( Cheesery cheesery = new Cheesery(); ),
                                     action( cheesery.addCheese( $cheese ); ),
                                     reverse( cheesery.removeCheese( $cheese ); ),
                                     result( cheesery ) );
    then
        // do something
    end

#### 7.8.3.8. Conditional Element `eval`

Figure 7.28. eval

The conditional element `eval` is essentially a catch-all which allows any semantic code (that returns a primitive boolean) to be executed. This code can refer to variables that were bound in the LHS of the rule, and functions in the rule package. Overuse of eval reduces the declarativeness of your rules and can result in a poorly performing engine. While `eval` can be used anywhere in the patterns, the best practice is to add it as the last conditional element in the LHS of a rule.

Evals cannot be indexed and thus are not as efficient as Field Constraints. However this makes them ideal for being used when functions return values that change over time, which is not allowed within Field Constraints.

For folks who are familiar with Drools 2.x lineage, the old Drools parameter and condition tags are equivalent to binding a variable to an appropriate type, and then using it in an eval node.

    p1 : Parameter()
    p2 : Parameter()
    eval( p1.getList().containsKey( p2.getItem() ) )

    p1 : Parameter()
    p2 : Parameter()
    // call function isValid in the LHS
    eval( isValid( p1, p2 ) )

#### 7.8.3.9. Railroad diagrams

### 7.8.4. The Right Hand Side (then)

#### 7.8.4.1. Usage

The Right Hand Side (RHS) is a common name for the consequence or action part of the rule; this part should contain a list of actions to be executed. It is bad practice to use imperative or conditional code in the RHS of a rule; as a rule should be atomic in nature - "when this, then do this", not "when this, maybe do this". The RHS part of a rule should also be kept small, thus keeping it declarative and readable. If you find you need imperative and/or conditional code in the RHS, then maybe you should be breaking that rule down into multiple rules. The main purpose of the RHS is to insert, delete or modify working memory data. To assist with that there are a few convenience methods you can use to modify working memory; without having to first reference a working memory instance.

`update(`object, handle`);` will tell the engine that an object has changed (one that has been bound to something on the LHS) and rules may need to be reconsidered.

`update(`object`);` can also be used; here the Knowledge Helper will look up the facthandle for you, via an identity check, for the passed object. (Note that if you provide Property Change Listeners to your Java beans that you are inserting into the engine, you can avoid the need to call `update()` when the object changes.). After a fact's field values have changed you must call update before changing another fact, or you will cause problems with the indexing within the rule engine. The modify keyword avoids this problem.

`insert(new` Something`());` will place a new object of your creation into the Working Memory.

`insertLogical(new` Something`());` is similar to insert, but the object will be automatically deleted when there are no more facts to support the truth of the currently firing rule.

`delete(`handle`);` removes an object from Working Memory.

These convenience methods are basically macros that provide short cuts to the `KnowledgeHelper` instance that lets you access your Working Memory from rules files. The predefined variable `drools` of type `KnowledgeHelper` lets you call several other useful methods. (Refer to the `KnowledgeHelper` interface documentation for more advanced operations).

- The call `drools.halt()` terminates rule execution immediately. This is required for returning control to the point whence the current session was put to work with `fireUntilHalt()`.

- Methods `insert(Object o)`, `update(Object o)` and `delete(Object o)` can be called on `drools` as well, but due to their frequent use they can be called without the object reference.

- `drools.getWorkingMemory()` returns the `WorkingMemory` object.

- `drools.setFocus( String s)` sets the focus to the specified agenda group.

- `drools.getRule().getName()`, called from a rule's RHS, returns the name of the rule.

- `drools.getTuple()` returns the Tuple that matches the currently executing rule, and `drools.getActivation()` delivers the corresponding Activation. (These calls are useful for logging and debugging purposes.)

The full Knowledge Runtime API is exposed through another predefined variable, `kcontext`, of type `KieContext`. Its method `getKieRuntime()` delivers an object of type `KieRuntime`, which, in turn, provides access to a wealth of methods, many of which are quite useful for coding RHS logic.

- The call `kcontext.getKieRuntime().halt()` terminates rule execution immediately.

- The accessor `getAgenda()` returns a reference to this session's `Agenda`, which in turn provides access to the various rule groups: activation groups, agenda groups, and rule flow groups. A fairly common paradigm is the activation of some agenda group, which could be done with the lengthy call:

      // give focus to the agenda group CleanUp
      kcontext.getKieRuntime().getAgenda().getAgendaGroup( "CleanUp" ).setFocus();

  (You can achieve the same using `drools.setFocus( "CleanUp" )`.)

- To run a query, you call `getQueryResults(String query)`, whereupon you may process the results, as explained in section Query.

- A set of methods dealing with event management lets you, among other things, add and remove event listeners for the Working Memory and the Agenda.

- Method `getKieBase()` returns the `KieBase` object, the backbone of all the Knowledge in your system, and the originator of the current session.

- You can manage globals with `setGlobal(...)`, `getGlobal(...)` and `getGlobals()`.

- Method `getEnvironment()` returns the runtime's `Environment` which works much like what you know as your operating system's environment.

#### 7.8.4.2. The `modify` Statement

This language extension provides a structured approach to fact updates. It combines the update operation with a number of setter calls to change the object's fields. This is the syntax schema for the `modify` statement:

    modify ( <fact-expression> ) {
        <expression> [ , <expression> ]*
    }

The parenthesized <fact-expression> must yield a fact object reference. The expression list in the block should consist of setter calls for the given object, to be written without the usual object reference, which is automatically prepended by the compiler.

The example illustrates a simple fact modification.

Example 7.78. A modify statement

    rule "modify stilton"
    when
        $stilton : Cheese(type == "stilton")
    then
        modify( $stilton ){
            setPrice( 20 ),
            setAge( "overripe" )
        }
    end

The advantages in using the modify statment are particularly clear when used in conjuction with fine grained property change listeners. See the corresponding section for more details.

### 7.8.5. Conditional named consequences

Sometimes the constraint of having one single consequence for each rule can be somewhat limiting and leads to verbose and difficult to be maintained repetitions like in the following example:

    rule "Give 10% discount to customers older than 60"
    when
        $customer : Customer( age > 60 )
    then
        modify($customer) { setDiscount( 0.1 ) };
    end

    rule "Give free parking to customers older than 60"
    when
        $customer : Customer( age > 60 )
        $car : Car ( owner == $customer )
    then
        modify($car) { setFreeParking( true ) };
    end

It is already possible to partially overcome this problem by making the second rule extending the first one like in:

    rule "Give 10% discount to customers older than 60"
    when
        $customer : Customer( age > 60 )
    then
        modify($customer) { setDiscount( 0.1 ) };
    end

    rule "Give free parking to customers older than 60"
        extends "Give 10% discount to customers older than 60"
    when
        $car : Car ( owner == $customer )
    then
        modify($car) { setFreeParking( true ) };
    end

Anyway this feature makes it possible to define more labelled consequences other than the default one in a single rule, so, for example, the 2 former rules can be compacted in only one like it follows:

    rule "Give 10% discount and free parking to customers older than 60"
    when
        $customer : Customer( age > 60 )
        do[giveDiscount]
        $car : Car ( owner == $customer )
    then
        modify($car) { setFreeParking( true ) };
    then[giveDiscount]
        modify($customer) { setDiscount( 0.1 ) };
    end

This last rule has 2 consequences, the usual default one, plus another one named "giveDiscount" that is activated, using the keyword do, as soon as a customer older than 60 is found in the knowledge base, regardless of the fact that he owns a car or not. The activation of a named consequence can be also guarded by an additional condition like in this further example:

    rule "Give free parking to customers older than 60 and 10% discount to golden ones among them"
    when
        $customer : Customer( age > 60 )
        if ( type == "Golden" ) do[giveDiscount]
        $car : Car ( owner == $customer )
    then
        modify($car) { setFreeParking( true ) };
    then[giveDiscount]
        modify($customer) { setDiscount( 0.1 ) };
    end

The condition in the if statement is always evaluated on the pattern immediately preceding it. In the end this last, a bit more complicated, example shows how it is possible to switch over different conditions using a nested if/else statement:

    rule "Give free parking and 10% discount to over 60 Golden customer and 5% to Silver ones"
    when
        $customer : Customer( age > 60 )
        if ( type == "Golden" ) do[giveDiscount10]
        else if ( type == "Silver" ) break[giveDiscount5]
        $car : Car ( owner == $customer )
    then
        modify($car) { setFreeParking( true ) };
    then[giveDiscount10]
        modify($customer) { setDiscount( 0.1 ) };
    then[giveDiscount5]
        modify($customer) { setDiscount( 0.05 ) };
    end

Here the purpose is to give a 10% discount AND a free parking to Golden customers over 60, but only a 5% discount (without free parking) to the Silver ones. This result is achieved by activating the consequence named "giveDiscount5" using the keyword break instead of do. In fact do just schedules a consequence in the agenda, allowing the remaining part of the LHS to continue of being evaluated as per normal, while break also blocks any further pattern matching evaluation. Note, of course, that the activation of a named consequence not guarded by any condition with break doesn't make sense (and generates a compile time error) since otherwise the LHS part following it would be never reachable.

### 7.8.6. A Note on Auto-boxing and Primitive Types

Drools attempts to preserve numbers in their primitive or object wrapper form, so a variable bound to an int primitive when used in a code block or expression will no longer need manual unboxing; unlike Drools 3.0 where all primitives were autoboxed, requiring manual unboxing. A variable bound to an object wrapper will remain as an object; the existing JDK 1.5 and JDK 5 rules to handle auto-boxing and unboxing apply in this case. When evaluating field constraints, the system attempts to coerce one of the values into a comparable format; so a primitive is comparable to an object wrapper.

## 7.9. Query

Figure 7.29. query

A query is a simple way to search the working memory for facts that match the stated conditions. Therefore, it contains only the structure of the LHS of a rule, so that you specify neither "when" nor "then". A query has an optional set of parameters, each of which can be optionally typed. If the type is not given, the type Object is assumed. The engine will attempt to coerce the values as needed. Query names are global to the KieBase; so do not add queries of the same name to different packages for the same RuleBase.

To return the results use `ksession.getQueryResults("name")`, where "name" is the query's name. This returns a list of query results, which allow you to retrieve the objects that matched the query.

The first example presents a simple query for all the people over the age of 30. The second one, using parameters, combines the age limit with a location.

Example 7.79. Query People over the age of 30

    query "people over the age of 30"
        person : Person( age > 30 )
    end

Example 7.80. Query People over the age of x, and who live in y

    query "people over the age of x"  (int x, String y)
        person : Person( age > x, location == y )
    end

We iterate over the returned QueryResults using a standard "for" loop. Each element is a QueryResultsRow which we can use to access each of the columns in the tuple. These columns can be accessed by bound declaration name or index position.

Example 7.81. Query People over the age of 30

    QueryResults results = ksession.getQueryResults( "people over the age of 30" );
    System.out.println( "we have " + results.size() + " people over the age  of 30" );

    System.out.println( "These people are are over 30:" );

    for ( QueryResultsRow row : results ) {
        Person person = ( Person ) row.get( "person" );
        System.out.println( person.getName() + "\n" );
    }

Support for positional syntax has been added for more compact code. By default the declared type order in the type declaration matches the argument position. But it possible to override these using the @position annotation. This allows patterns to be used with positional arguments, instead of the more verbose named arguments.

    declare Cheese
        name : String @position(1)
        shop : String @position(2)
        price : int @position(0)
    end

The @Position annotation, in the org.drools.definition.type package, can be used to annotate original pojos on the classpath. Currently only fields on classes can be annotated. Inheritance of classes is supported, but not interfaces or methods. The isContainedIn query below demonstrates the use of positional arguments in a pattern; `Location(x, y;)` instead of `Location( thing == x, location == y).`

Queries can now call other queries, this combined with optional query arguments provides derivation query style backward chaining. Positional and named syntax is supported for arguments. It is also possible to mix both positional and named, but positional must come first, separated by a semi colon. Literal expressions can be passed as query arguments, but at this stage you cannot mix expressions with variables. Here is an example of a query that calls another query. Note that 'z' here will always be an 'out' variable. The '?' symbol means the query is pull only, once the results are returned you will not receive further results as the underlying data changes.

    declare Location
        thing : String
        location : String
    end

    query isContainedIn( String x, String y )
        Location(x, y;)
        or
        ( Location(z, y;) and ?isContainedIn(x, z;) )
    end

As previously mentioned you can use live "open" queries to reactively receive changes over time from the query results, as the underlying data it queries against changes. Notice the "look" rule calls the query without using '?'.

    query isContainedIn( String x, String y )
        Location(x, y;)
        or
        ( Location(z, y;) and isContainedIn(x, z;) )
    end

    rule look when
        Person( $l : likes )
        isContainedIn( $l, 'office'; )
    then
       insertLogical( $l 'is in the office' );
    end

Drools supports unification for derivation queries, in short this means that arguments are optional. It is possible to call queries from Java leaving arguments unspecified using the static field org.drools.core.runtime.rule.Variable.v - note you must use 'v' and not an alternative instance of Variable. These are referred to as 'out' arguments. Note that the query itself does not declare at compile time whether an argument is in or an out, this can be defined purely at runtime on each use. The following example will return all objects contained in the office.

    results = ksession.getQueryResults( "isContainedIn", new Object[] {  Variable.v, "office" } );
    l = new ArrayList<List<String>>();
    for ( QueryResultsRow r : results ) {
        l.add( Arrays.asList( new String[] { (String) r.get( "x" ), (String) r.get( "y" ) } ) );
    }

The algorithm uses stacks to handle recursion, so the method stack will not blow up.

The following is not yet supported:

- List and Map unification

- Variables for the fields of facts

- Expression unification - pred( X, X + 1, X * Y / 7 )

## 7.10. Domain Specific Languages

Domain Specific Languages (or DSLs) are a way of creating a rule language that is dedicated to your problem domain. A set of DSL definitions consists of transformations from DSL "sentences" to DRL constructs, which lets you use of all the underlying rule language and engine features. Given a DSL, you write rules in DSL rule (or DSLR) files, which will be translated into DRL files.

DSL and DSLR files are plain text files, and you can use any text editor to create and modify them. But there are also DSL and DSLR editors, both in the IDE as well as in the web based BRMS, and you can use those as well, although they may not provide you with the full DSL functionality.

### 7.10.1. When to Use a DSL

DSLs can serve as a layer of separation between rule authoring (and rule authors) and the technical intricacies resulting from the modelling of domain object and the rule engine's native language and methods. If your rules need to be read and validated by domain experts (such as business analysts, for instance) who are not programmers, you should consider using a DSL; it hides implementation details and focuses on the rule logic proper. DSL sentences can also act as "templates" for conditional elements and consequence actions that are used repeatedly in your rules, possibly with minor variations. You may define DSL sentences as being mapped to these repeated phrases, with parameters providing a means for accommodating those variations.

DSLs have no impact on the rule engine at runtime, they are just a compile time feature, requiring a special parser and transformer.

### 7.10.2. DSL Basics

The Drools DSL mechanism allows you to customise conditional expressions and consequence actions. A global substitution mechanism ("keyword") is also available.

Example 7.82. Example DSL mapping

    [when]Something is {colour}=Something(colour=="{colour}")

In the preceding example, `[when]` indicates the scope of the expression, i.e., whether it is valid for the LHS or the RHS of a rule. The part after the bracketed keyword is the expression that you use in the rule; typically a natural language expression, but it doesn't have to be. The part to the right of the equal sign ("=") is the mapping of the expression into the rule language. The form of this string depends on its destination, RHS or LHS. If it is for the LHS, then it ought to be a term according to the regular LHS syntax; if it is for the RHS then it might be a Java statement.

Whenever the DSL parser matches a line from the rule file written in the DSL with an expression in the DSL definition, it performs three steps of string manipulation. First, it extracts the string values appearing where the expression contains variable names in braces (here: `{colour}`). Then, the values obtained from these captures are then interpolated wherever that name, again enclosed in braces, occurs on the right hand side of the mapping. Finally, the interpolated string replaces whatever was matched by the entire expression in the line of the DSL rule file.

Note that the expressions (i.e., the strings on the left hand side of the equal sign) are used as regular expressions in a pattern matching operation against a line of the DSL rule file, matching all or part of a line. This means you can use (for instance) a '?' to indicate that the preceding character is optional. One good reason to use this is to overcome variations in natural language phrases of your DSL. But, given that these expressions are regular expression patterns, this also means that all "magic" characters of Java's pattern syntax have to be escaped with a preceding backslash ('\').

It is important to note that the compiler transforms DSL rule files line by line. In the above example, all the text after "Something is " to the end of the line is captured as the replacement value for "{colour}", and this is used for interpolating the target string. This may not be exactly what you want. For instance, when you intend to merge different DSL expressions to generate a composite DRL pattern, you need to transform a DSLR line in several independent operations. The best way to achieve this is to ensure that the captures are surrounded by characteristic text - words or even single characters. As a result, the matching operation done by the parser plucks out a substring from somewhere within the line. In the example below, quotes are used as distinctive characters. Note that the characters that surround the capture are not included during interpolation, just the contents between them.

As a rule of thumb, use quotes for textual data that a rule editor may want to enter. You can also enclose the capture with words to ensure that the text is correctly matched. Both is illustrated by the following example. Note that a single line such as `Something is "green" and another solid thing` is now correctly expanded.

Example 7.83. Example with quotes

    [when]something is "{colour}"=Something(colour=="{colour}")
    [when]another {state} thing=OtherThing(state=="{state})"

It is a good idea to avoid punctuation (other than quotes or apostrophes) in your DSL expressions as much as possible. The main reason is that punctuation is easy to forget for rule authors using your DSL. Another reason is that parentheses, the period and the question mark are magic characters, requiring escaping in the DSL definition.

In a DSL mapping, the braces "{" and "}" should only be used to enclose a variable definition or reference, resulting in a capture. If they should occur literally, either in the expression or within the replacement text on the right hand side, they must be escaped with a preceding backslash ("\"):

    [then]do something= if (foo) \{ doSomething(); \}

## Note

If braces "{" and "}" should appear in the replacement string of a DSL definition, escape them with a backslash ('\').

Example 7.84. Examples of DSL mapping entries

    # This is a comment to be ignored.
    [when]There is a person with name of "{name}"=Person(name=="{name}")
    [when]Person is at least {age} years old and lives in "{location}"=
          Person(age >= {age}, location=="{location}")
    [then]Log "{message}"=System.out.println("{message}");
    [when]And = and

Given the above DSL examples, the following examples show the expansion of various DSLR snippets:

Example 7.85. Examples of DSL expansions

    There is a person with name of "Kitty"
       ==> Person(name="Kitty")
    Person is at least 42 years old and lives in "Atlanta"
       ==> Person(age >= 42, location="Atlanta")
    Log "boo"
       ==> System.out.println("boo");
    There is a person with name of "Bob" and Person is at least 30 years old and lives in "Utah"
       ==> Person(name="Bob") and Person(age >= 30, location="Utah")

## Note

Don't forget that if you are capturing plain text from a DSL rule line and want to use it as a string literal in the expansion, you must provide the quotes on the right hand side of the mapping.

You can chain DSL expressions together on one line, as long as it is clear to the parser where one ends and the next one begins and where the text representing a parameter ends. (Otherwise you risk getting all the text until the end of the line as a parameter value.) The DSL expressions are tried, one after the other, according to their order in the DSL definition file. After any match, all remaining DSL expressions are investigated, too.

The resulting DRL text may consist of more than one line. Line ends are in the replacement text are written as `\n`.

### 7.10.3. Adding Constraints to Facts

A common requirement when writing rule conditions is to be able to add an arbitrary combination of constraints to a pattern. Given that a fact type may have many fields, having to provide an individual DSL statement for each combination would be plain folly.

The DSL facility allows you to add constraints to a pattern by a simple convention: if your DSL expression starts with a hyphen (minus character, "-") it is assumed to be a field constraint and, consequently, is is added to the last pattern line preceding it.

For an example, lets take look at class `Cheese`, with the following fields: type, price, age and country. We can express some LHS condition in normal DRL like the following

    Cheese(age < 5, price == 20, type=="stilton", country=="ch")

The DSL definitions given below result in three DSL phrases which may be used to create any combination of constraint involving these fields.

    [when]There is a Cheese with=Cheese()
    [when]- age is less than {age}=age<{age}
    [when]- type is '{type}'=type=='{type}'
    [when]- country equal to '{country}'=country=='{country}'

You can then write rules with conditions like the following:

    There is a Cheese with
            - age is less than 42
            - type is 'stilton'

The parser will pick up a line beginning with "-" and add it as a constraint to the preceding pattern, inserting a comma when it is required. For the preceding example, the resulting DRL is:

    Cheese(age<42, type=='stilton')

Combining all all numeric fields with all relational operators (according to the DSL expression "age is less than..." in the preceding example) produces an unwieldy amount of DSL entries. But you can define DSL phrases for the various operators and even a generic expression that handles any field constraint, as shown below. (Notice that the expression definition contains a regular expression in addition to the variable name.)

    [when][]is less than or equal to=<=
    [when][]is less than=<
    [when][]is greater than or equal to=>=
    [when][]is greater than=>
    [when][]is equal to===
    [when][]equals===
    [when][]There is a Cheese with=Cheese()
    [when][]- {field:\w*} {operator} {value:\d*}={field} {operator} {value}

Given these DSL definitions, you can write rules with conditions such as:

    There is a Cheese with
       - age is less than 42
       - rating is greater than 50
       - type equals 'stilton'

In this specific case, a phrase such as "is less than" is replaced by `<`, and then the line matches the last DSL entry. This removes the hyphen, but the final result is still added as a constraint to the preceding pattern. After processing all of the lines, the resulting DRL text is:

    Cheese(age<42, rating > 50, type=='stilton')

## Note

The order of the entries in the DSL is important if separate DSL expressions are intended to match the same line, one after the other.

### 7.10.4. Developing a DSL

A good way to get started is to write representative samples of the rules your application requires, and to test them as you develop. This will provide you with a stable framework of conditional elements and their constraints. Rules, both in DRL and in DSLR, refer to entities according to the data model representing the application data that should be subject to the reasoning process defined in rules. Notice that writing rules is generally easier if most of the data model's types are facts.

Given an initial set of rules, it should be possible to identify recurring or similar code snippets and to mark variable parts as parameters. This provides reliable leads as to what might be a handy DSL entry. Also, make sure you have a full grasp of the jargon the domain experts are using, and base your DSL phrases on this vocabulary.

You may postpone implementation decisions concerning conditions and actions during this first design phase by leaving certain conditional elements and actions in their DRL form by prefixing a line with a greater sign (">"). (This is also handy for inserting debugging statements.)

During the next development phase, you should find that the DSL configuration stabilizes pretty quickly. New rules can be written by reusing the existing DSL definitions, or by adding a parameter to an existing condition or consequence entry.

Try to keep the number of DSL entries small. Using parameters lets you apply the same DSL sentence for similar rule patterns or constraints. But do not exaggerate: authors using the DSL should still be able to identify DSL phrases by some fixed text.

### 7.10.5. DSL and DSLR Reference

A DSL file is a text file in a line-oriented format. Its entries are used for transforming a DSLR file into a file according to DRL syntax.

- A line starting with "#" or "//" (with or without preceding white space) is treated as a comment. A comment line starting with "#/" is scanned for words requesting a debug option, see below.

- Any line starting with an opening bracket ("[") is assumed to be the first line of a DSL entry definition.

- Any other line is appended to the preceding DSL entry definition, with the line end replaced by a space.

A DSL entry consists of the following four parts:

- A scope definition, written as one of the keywords "when" or "condition", "then" or "consequence", "*" and "keyword", enclosed in brackets ("[" and "]"). This indicates whether the DSL entry is valid for the condition or the consequence of a rule, or both. A scope indication of "keyword" means that the entry has global significance, i.e., it is recognized anywhere in a DSLR file.

- A type definition, written as a Java class name, enclosed in brackets. This part is optional unless the the next part begins with an opening bracket. An empty pair of brackets is valid, too.

- A DSL expression consists of a (Java) regular expression, with any number of embedded variable definitions, terminated by an equal sign ("="). A variable definition is enclosed in braces ("{" and "}"). It consists of a variable name and two optional attachments, separated by colons (":"). If there is one attachment, it is a regular expression for matching text that is to be assigned to the variable; if there are two attachments, the first one is a hint for the GUI editor and the second one the regular expression.

  Note that all characters that are "magic" in regular expressions must be escaped with a preceding backslash ("\") if they should occur literally within the expression.

- The remaining part of the line after the delimiting equal sign is the replacement text for any DSLR text matching the regular expression. It may contain variable references, i.e., a variable name enclosed in braces. Optionally, the variable name may be followed by an exclamation mark ("!") and a transformation function, see below.

  Note that braces ("{" and "}") must be escaped with a preceding backslash ("\") if they should occur literally within the replacement string.

Debugging of DSL expansion can be turned on, selectively, by using a comment line starting with "#/" which may contain one or more words from the table presented below. The resulting output is written to standard output.

Table 7.2. Debug options for DSL expansion

Word | Description
--- | ---
result | Prints the resulting DRL text, with line numbers.
steps | Prints each expansion step of condition and consequence lines.
keyword | Dumps the internal representation of all DSL entries with scope "keyword".
when | Dumps the internal representation of all DSL entries with scope "when" or "*".
then | Dumps the internal representation of all DSL entries with scope "then" or "*".
usage | Displays a usage statistic of all DSL entries.

Below are some sample DSL definitions, with comments describing the language features they illustrate.

    # Comment: DSL examples

    #/ debug: display result and usage

    # keyword definition: replaces "regula" by "rule"
    [keyword][]regula=rule

    # conditional element: "T" or "t", "a" or "an", convert matched word
    [when][][Tt]here is an? {entity:\w+}=
            ${entity!lc}: {entity!ucfirst} ()

    # consequence statement: convert matched word, literal braces
    [then][]update {entity:\w+}=modify( ${entity!lc} )\{ \}

The transformation of a DSLR file proceeds as follows:

1. The text is read into memory.

2. Each of the "keyword" entries is applied to the entire text. First, the regular expression from the keyword definition is modified by replacing white space sequences with a pattern matching any number of white space characters, and by replacing variable definitions with a capture made from the regular expression provided with the definition, or with the default (".*?"). Then, the DSLR text is searched exhaustively for occurrences of strings matching the modified regular expression. Substrings of a matching string corresponding to variable captures are extracted and replace variable references in the corresponding replacement text, and this text replaces the matching string in the DSLR text.

3. Sections of the DSLR text between "when" and "then", and "then" and "end", respectively, are located and processed in a uniform manner, line by line, as described below.

   For a line, each DSL entry pertaining to the line's section is taken in turn, in the order it appears in the DSL file. Its regular expression part is modified: white space is replaced by a pattern matching any number of white space characters; variable definitions with a regular expression are replaced by a capture with this regular expression, its default being ".*?". If the resulting regular expression matches all or part of the line, the matched part is replaced by the suitably modified replacement text.

   Modification of the replacement text is done by replacing variable references with the text corresponding to the regular expression capture. This text may be modified according to the string transformation function given in the variable reference; see below for details.

   If there is a variable reference naming a variable that is not defined in the same entry, the expander substitutes a value bound to a variable of that name, provided it was defined in one of the preceding lines of the current rule.

4. If a DSLR line in a condition is written with a leading hyphen, the expanded result is inserted into the last line, which should contain a pattern CE, i.e., a type name followed by a pair of parentheses. if this pair is empty, the expanded line (which should contain a valid constraint) is simply inserted, otherwise a comma (",") is inserted beforehand.

   If a DSLR line in a consequence is written with a leading hyphen, the expanded result is inserted into the last line, which should contain a "modify" statement, ending in a pair of braces ("{" and "}"). If this pair is empty, the expanded line (which should contain a valid method call) is simply inserted, otherwise a comma (",") is inserted beforehand.

## Note

It is currently not possible to use a line with a leading hyphen to insert text into other conditional element forms (e.g., "accumulate") or it may only work for the first insertion (e.g., "eval").

All string transformation functions are described in the following table.

Table 7.3. String transformation functions

Name | Description
--- | ---
uc | Converts all letters to upper case.
lc | Converts all letters to lower case.
ucfirst | Converts the first letter to upper case, and all other letters to lower case.
num | Extracts all digits and "-" from the string. If the last two digits in the original string are preceded by "." or ",", a decimal period is inserted in the corresponding position.
a?b/c | Compares the string with string a, and if they are equal, replaces it with b, otherwise with c. But c can be another triplet a, b, c, so that the entire structure is, in fact, a translation table.

The following DSL examples show how to use string transformation functions.

    # definitions for conditions
    [when][]There is an? {entity}=${entity!lc}: {entity!ucfirst}()
    [when][]- with an? {attr} greater than {amount}={attr} <= {amount!num}
    [when][]- with a {what} {attr}={attr} {what!positive?>0/negative?%lt;0/zero?==0/ERROR}

A file containing a DSL definition has to be put under the resources folder or any of its subfolders like any other drools artifact. It must have the extension `.dsl`, or alternatively be marked with type `ResourceType.DSL`. when programmatically added to a `KieFileSystem`. For a file using DSL definition, the extension `.dslr` should be used, while it can be added to a `KieFileSystem` with type `ResourceType.DSLR`.

For parsing and expanding a DSLR file the DSL configuration is read and supplied to the parser. Thus, the parser can "recognize" the DSL expressions and transform them into native rule language expressions.

- PrevChapter 6. User Guide
- Up
- Home
- NextChapter 8. Complex Event Processing