Chapter 15. Additional Declarations
15.1. Declaring Metadata for Existing Types
JBoss Rules 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.
15.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
15.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
15.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 )
15.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.
15.6. Accessing Declared Types from the Application Code
Sometimes applications need to access and handle facts from the declared types. In such cases, JBoss Rules provides a simplified API for the most common fact handling the application wishes to do. A declared fact will belong to the package where it was declared.
15.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
15.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: 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" );
15.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.
15.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 end
15.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.
15.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 ); end
15.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.
15.14. @Traitable Example
This illustrates the use of the @traitable annotation:
declare Customer @Traitable code : String balance : long end
15.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.
15.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 ); end
15.17. Hidden Fields
Hidden fields are fields in the core class not exposed by the interface.
15.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.
15.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.
15.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 end
15.21. Wrapper with isA Annotation Example
This illustrates a wrapper in use with the isA annotation:
$sc : GoldenCustomer( $maxExpense : maxExpense > 1000, this isA "SeniorCustomer" )
15.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.
15.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
15.24. Timer Attribute Example
This is what the
timer
attribute looks like:
timer ( int: <initial delay> <repeat interval>? ) timer ( int: 30s ) timer ( int: 30s 5m ) timer ( cron: <cron expression> ) timer ( cron:* 0/15 * * * ? )
15.25. Timers
The following timers are available in JBoss Rules:
- Interval
- Interval (indicated by "int:") timers follow the semantics of java.util.Timer objects, with an initial delay and an optional repeat interval.
- Cron
- Cron (indicated by "cron:") timers follow standard Unix cron expressions.
15.26. Cron Timer Example
This is what the Cron timer looks like:
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
15.27. Calendars
Calendars are used to control when rules can fire. JBoss Rules uses the Quartz calendar.
15.28. Quartz Calendar Example
This is what the Quartz calendar looks like:
Calendar weekDayCal = QuartzHelper.quartzCalendarAdapter(org.quartz.Calendar quartzCal)
15.29. Registering a Calendar
Procedure 15.1. Task
- Start a StatefulKnowledgeSession.
- Use the following code to register the calendar:
ksession.getCalendars().set( "weekday", weekDayCal );
- If you wish to utilize the calendar and a timer together, use the following code:
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
15.30. 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.
15.31. Conditional Elements
Conditional elements work on one or more patterns. The most common conditional element is
and
. It is implicit when you have multiple patterns in the LHS of a rule that is not connected in any way.
15.32. Rule Without a Conditional Element Example
This is what a rule without a conditional element looks like:
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