Type Declaration

Note

(updated to Drools 5.0)

Warning

FIXME: add syntax diagram for declare

Type Declarations have two main goals in the rules engine: allow the declaration of new types and/or allow the declaration of metadata for types.

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.

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 3 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, 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 bytecode generate at compile time a POJO that implements the fact type. The generated Java class will be a one-to-one javabean 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;

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


Since it is a simple POJO, the generated class 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
    System.out.println( "The name of the person is "+ )
    // lets insert Mark, that is Bob's mate
    Person mark = new Person();
    mark.setName("Mark");
    insert( mark );
end


Declaring Metadata

Metadata may be assigned to several different constructions in Drools, like fact types, fact attributes and rules. Drools uses the @ symbol to introduce metadata, and it always uses the form:

@matadata_key( metadata_value )

The parenthesis and the metadata_value are 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 an arbitrary 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 fields of a fact type are assigned to the fact type, while metadata declared after an attribute are assigned to the attribute in particular.

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 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 value, and so the parenthesis and the value were omitted.

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, just to the following:

Example 7.17. 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, usually it is shorter to add the import and use the short class name everywhere.

Example 7.18. declaring metadata using the fully qualified class name

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

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, specially 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 APIs, but as we know, that usually requires a lot of work for small results. This way, 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 bellow, Person will belong to the org.drools.examples package, and so the generated class fully qualified name will be: org.drools.examples.Person.

Example 7.19. 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. As so, these classes are not available for direct reference from the application.

Drools then provides an interface through which the 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.20. handling declared fact types through the API

// get a reference to a knowledge base with a declared type:
KnowledgeBase 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
StatefulKnowledgeSession 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 read all attributes at once, populating a Map.

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