Show Table of Contents
8.9. Type Declaration
8.9.1. Declaring Metadata for Existing Types
JBoss BRMS 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.
8.9.2. Declaring Metadata for Existing Types Example
This example shows how to declare metadata for an existing type:
import org.drools.examples.Person declare Person @author( Bob ) @dateOfCreation( 01-Feb-2009 ) end
8.9.3. Declaring Metadata Using a Fully Qualified Class Name Example
This example shows how you can declare metadata using the fully qualified class name instead of using the import annotation:
declare org.drools.examples.Person @author( Bob ) @dateOfCreation( 01-Feb-2009 ) end
8.9.4. Parametrized Constructors 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 )
8.9.5. Non-Typesafe Classes
The @typesafe( <boolean>) annotation 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 is useful when dealing with collections that do not have any generics or mixed type collections.
8.9.6. Accessing Declared Types from the Application Code
Sometimes applications need to access and handle facts from the declared types. In such cases, JBoss BRMS provides a simplified API for the most common fact handling the application wishes to do. A declared fact belongs to the package where it is declared.
8.9.7. Declaring a Type
This illustrates the process of declaring a type:
package org.drools.examples import java.util.Date declare Person name : String dateOfBirth : Date address : Address end
8.9.8. Handling Declared Fact Types Through the API Example
This example illustrates the handling of declared fact types through the API:
// get a reference to a knowledge base with a declared type:
Kie 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.
8.9.9. Type Declaration Extends
Type declarations support the 'extends' keyword for inheritance. To extend a type declared in Java by a DRL declared subtype, repeat the supertype in a declare statement without any fields.
8.9.10. Type Declaration Extends Example
This illustrates the use of the
extends annotation:
import org.people.Person
declare Person
end
declare Student extends Person
school : String
end
declare LongTermStudent extends Student
years : int
course : String
end8.9.11. Traits
Traits allow you to model multiple dynamic types which do not fit naturally in a class hierarchy. A trait is an interface that can be applied (and eventually removed) to an individual object at runtime. To create a trait out of an interface, a
@format(trait) annotation is added to its declaration in DRL.
8.9.12. Traits Example
declare GoldenCustomer
@format(trait)
// fields will map to getters/setters
code : String
balance : long
discount : int
maxExpense : long
end
In order to apply a trait to an object, the new don keyword is added:
when
$c : Customer()
then
GoldenCustomer gc = don( $c, Customer.class );
end8.9.13. Core Objects and Traits
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. Any object can don a trait. For efficiency reasons, however, you can add the @Traitable annotation to a declared bean class to reduce the amount of glue code that the compiler will have to generate. This is optional and will not change the behavior of the engine.
8.9.14. @Traitable Example
This illustrates the use of the @traitable annotation:
declare Customer
@Traitable
code : String
balance : long
end8.9.15. Writing Rules with Traits
The only connection between core classes and trait interfaces is at the proxy level. (That is, 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. 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.
8.9.16. Rules with Traits Example
This example illustrates the trait interface being mapped to a field:
when
$o: OrderItem( $p : price, $code : custCode )
$c: GoldenCustomer( code == $code, $a : balance, $d: discount )
then
$c.setBalance( $a - $p*$d );
end8.9.17. Hidden Fields
Hidden fields are fields in the core class not exposed by the interface.
8.9.18. The Two-Part Proxy
The two-part proxy has been developed to deal with soft and hidden fields which are not processed intuitively. Internally, proxies are formed by a proper proxy and a wrapper. The former implements the interface, while the latter manages the core object fields, implementing a name/value map to supports soft fields. The proxy uses both the core object and the map wrapper to implement the interface, as needed.
8.9.19. Wrappers
The wrapper provides a looser form of typing when writing rules. However, it has also other uses. The wrapper is specific to the object it wraps, regardless of how many traits have been attached to an object. All the proxies on the same object will share the same wrapper. Additionally, the wrapper contains a back-reference to all proxies attached to the wrapped object, effectively allowing traits to see each other.
8.9.20. Wrapper Example
This is an example of using the wrapper:
when
$sc : GoldenCustomer( $c : code, // hard getter
$maxExpense : maxExpense > 1000 // soft getter
)
then
$sc.setDiscount( ... ); // soft setter
end8.9.21. Wrapper with isA Annotation Example
This illustrates a wrapper in use with the isA annotation:
$sc : GoldenCustomer( $maxExpense : maxExpense > 1000,
this isA "SeniorCustomer"
)8.9.22. Removing Traits
The business logic may require that a trait is removed from a wrapped object. There are two ways to do so:
- Logical don
- Results in a logical insertion of the proxy resulting from the traiting operation.
then don( $x, // core object Customer.class, // trait class true // optional flag for logical insertion ) - The shed keyword
- The shed keyword causes the retraction of the proxy corresponding to the given argument type
then Thing t = shed( $x, GoldenCustomer.class )This operation returns another proxy implementing the org.drools.factmodel.traits.Thing interface, where the getFields() and getCore() methods are defined. Internally, 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.
8.9.23. Rule Syntax Example
This is an example of the syntax you should use when creating a rule:
rule "<name>"
<attribute>*
when
<conditional element>*
then
<action>*
end
Where did the comment section go?
Red Hat's documentation publication system recently went through an upgrade to enable speedier, more mobile-friendly content. We decided to re-evaluate our commenting platform to ensure that it meets your expectations and serves as an optimal feedback mechanism. During this redesign, we invite your input on providing feedback on Red Hat documentation via the discussion platform.