(updated to Drools 5.0)
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: Drools works out of the box with plain POJOs as facts. Although, sometimes the users may want to define the model directly into the rules engine, without worrying to create their models in a lower level language like Java. Another 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 are 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.
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
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:
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.
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
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.