Chapter 2. Drools Release Notes

Table of Contents

What is new in Drools 5.0
Drools API
Drools Guvnor
Drools Expert
Drools Flow
Drools Fusion
Eclipse IDE
What is new in Drools 4.0
Language Expressiveness Enhancements
Core Engine Enhancements
IDE Enhancements
Business Rules Management System - BRMS
Miscellaneous Enhancements
Upgrade tips from Drools 3.0.x to Drools 4.0.x
API changes
Rule Language Changes
Drools Update Tool
DSL Grammars in Drools 4.0
Rule flow Update for 4.0.2

What is new in Drools 5.0

Drools 5.0 will be the launch of what we call the Business Logic integration Platform (BLiP) - the BRMs is dead :) The future is for a unified and integrated solution for Rules, Processes and CEP - this is what users want and this is what we are aiming for. Drools 5.0 will split up into 4 main sub projects, the documentation has already been split to reflect this:

  • Drools Guvnor (BRMS/BPMS)

  • Drools Expert (rule engine),

  • Drools Flow (process/workflow)

  • Drools Fusion (cep/temporal reasoning)

Drools API

Drools now has complete api/implementation separation that is no longer rules oriented. This is an important strategy as we move to support other forms of logic, such as workflow and event processing. The main change is that we are now knowledge oriented, instead of rule oriented. The module drools-api provide the interfaces and factories and we have made pains to provide much better javadocs, with lots of code snippets, than we did before. Drools-api also helps clearly show what is intended as a user api and what is just an engine api, drools-core and drools-compiler did not make this clear enough. The most common interfaces you will use are:

  • org.drools.builder.KnowledgeBuilder

  • org.drools.KnowledgeBase

  • org.drools.agent.KnowledgeAgent

  • org.drools.runtime.StatefulKnowledgeSession

  • org.drools.runtime.StatelessKnowledgeSession

Factory classes, with static methods, provide instances of the above interfaces. A pluggable provider approach is used to allow provider implementations to be wired up to the factories at runtime. The Factories you will most commonly used are:

  • org.drools.builder.KnowledgeBuilderFactory

  • org.drools.io.ResourceFactory

  • org.drools.KnowledgeBaseFactory

  • org.drools.agent.KnowledgeAgentFactory

Example 2.1. A Typical example to load a rule resource

KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newUrlResource( url ),
            ResourceType.DRL );
if ( kbuilder.hasErrors() ) {
  System.err.println( builder.getErrors().toString() );
}         

KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages( builder.getKnowledgePackages() );

StatefulKnowledgeSession ksession = knowledgeBase.newStatefulKnowledgeSession();
ksession.insert( new Fibonacci( 10 ) );
ksession.fireAllRules();

ksession.dispose();


A Typical example to load a process resource. Notice the ResourceType is changed, in accordance with the Resource type:

Example 2.2. A Typical example to load a process resource. Notice the ResourceType is changed, in accordance with the Resource type

KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newUrlResource( url ),
            ResourceType.DRF );
if ( kbuilder.hasErrors() ) {
  System.err.println( builder.getErrors().toString() );
}         

KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages( builder.getKnowledgePackages() );

StatefulKnowledgeSession ksession = knowledgeBase.newStatefulKnowledgeSession();
ksession.startProcess( "Buy Order Process" );

ksession.dispose();


'kbuilder', 'kbase', 'ksession' are the variable identifiers often used, the k prefix is for 'knowledge'.

Example 2.3. We have uniformed how decision trees are loaded, and they are now consistent with no need to pre generate the DRL with the spreadsheet compiler

DecisionTableConfiguration dtconf = KnowledgeBuilderFactory.newDecisionTableConfiguration();
dtconf.setInputType( DecisionTableInputType.XLS );
dtconf.setWorksheetName( "Tables_2" );
kbuilder.add( ResourceFactory.newUrlResource( "file://IntegrationExampleTest.xls" ),
            ResourceType.DTABLE,
            dtconf );


It is also possible to configure a KnowledgeBase using configuration, via a xml change set, instead of programmatically.

Example 2.4. Here is a simple change set

<change-set xmlns='http://drools.org/drools-5.0/change-set'
xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'
xs:schemaLocation='http://drools.org/drools-5.0/change-set change-set-5.0.xsd' >
  <add>
      <resource source='classpath:org/domain/someRules.drl' type='DRL' />
      <resource source='classpath:org/domain/aFlow.drf' type='DRF' />
  </add>
</change-set>


Example 2.5. And it is added just like any other ResourceType

KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newUrlResource( url ),
            ResourceType.ChangeSet );


The other big change for the KnowledgeAgent, compared to the RuleAgent, is that polling scanner is now a service. further to this there is an abstraction between the agent notification and the resource monitoring, to allow other mechanisms to be used other than polling.

Example 2.6. These services currently are not started by default, to start them do the following

ResourceFactory.getResourceChangeNotifierService().start();
ResourceFactory.getResourceChangeScannerService().start();


There are two new interfaces added, ResourceChangeNotifier and ResourceChangeMonitor. KnowlegeAgents subscribe for resource change notifications using the ResourceChangeNotifier implementation. The ResourceChangeNotifier is informed of resource changes by the added ResourceChangeMonitors. We currently only provide one out of the box monitor, ResourceChangeScannerService, which polls resources for changes. However the api is there for users to add their own monitors, and thus use a push based monitor such as JMS.

ResourceFactory.getResourceChangeNotifierService().addResourceChangeMonitor( myJmsMonitor);

Drools Guvnor

  • New look web tooling

    Figure 2.1. 


  • Web based decision table editor

    Figure 2.2. Web based decision table editor

    Web based decision table editor


  • Integrated scenario testing

    Figure 2.3. Running all scenarios

    Running all scenarios


    Figure 2.4. Running single scenario

    Running single scenario


  • WebDAV file based interface to repository

    Figure 2.5. WebDAV

    WebDAV


  • Declarative modelling of types (types that are not in pojos)

    Figure 2.6. >Declarative modelling

    >Declarative modelling


    This works with the new "declare" statement - you can now declare types in drl itself. You can then populate these without using a pojo (if you like). These types are then available in the rulebase.

  • Fine grained security (lock down access to the app per package or per category). Users who only have category permissions have limited UI capability (ideal for business users)

  • Execution server - access rules via XML or JSON for execution

  • Category rules allows you to set 'parent rules' for a category. Any rules appearing in the given category will 'extend' the rule specified - ie inherit the conditions/LHS. The base rule for the category can be set on package configuration tab. RHS is not inherited, only the LHS

  • Scenario runner detects infinite loops

  • Scenario runner can show event trace that was recorded by audit logger

  • DSL sentences in guided editor can now be set to show enums as a dropdown, dates as a date picker, booleans as a checkbox and use regular expressions to validate the inputs (DSL Widgets in Guvnor)

  • Functions can be edited with text editor

  • It is possible to add objects to global collections.

  • Translations to English, Spanish, Chinese and Japanese

Drools Expert

Asymmetrical Rete algorithm implementation

Shadow proxies are no longer needed. Shadow proxies protected the engine from information change on facts, which if occurred outside of the engine's control it could not be modified or retracted.

PackageBuilder can now build multiple namespaces

You no longer need to confine one PackageBuilder to one package namespace. Just keeping adding your DRLs for any namespace and getPackages() returns an array of Packages for each of the used namespaces.

Example 2.7. Getting multiple packages

Package[] packages = pkgBuilder.getPackages();


RuleBase attachment to PackageBuilder

It is now possible to attach a RuleBase to a PackageBuilder, this means that rules are built and added to the rulebase at the same time. PackageBuilder uses the Package instances of the actual RuleBase as it's source, removing the need for additional Package creation and merging that happens in the existing approach.

Example 2.8. Attaching RuleBase to PackageBuilder

RuleBase ruleBase = RuleBaseFactory.newRuleBase();
PackageBuilder pkgBuilder = new PackageBuilder( ruleBase, null );


Binary marshalling of stateful sessions

Stateful sessions can now saved and resumed at a later date. Pre-loaded data sessions can now be created. Pluggable strategies can be used for user object persistence, i.e. hibernate or identity maps.

Type Declaration

Drools now supports a new base construct called Type Declaration. This construct fulfils two purposes: the ability to declare fact metadata, and the ability to dynamically generate new fact types local to the rule engine. The Guvnor modelling tool uses this underneath. One example of the construct is:

Example 2.9. Declaring StockTick

declare StockTick
  @role( event )
  @timestamp( timestampAttr )

  companySymbol : String
  stockPrice : double
  timestampAttr : long
end


Declaring Fact Metadata

To declare and associate fact metadata, just use the @ symbol for each metadata ID you want to declare. Example:

Example 2.10. Declaring metadata

declare StockTick
  @role( event )
end


Triggering Bean Generation

To activate the dynamic bean generation, just add fields and types to your type declaration:

Example 2.11. Declaring Person

declare Person
  name : String
  age : int
end


DSL improvements

A series of DSL improvements were implemented, including a completely new parser and the ability to declare matching masks for matching variables. For instance, one can constrain a phone number field to a 2-digit country code + 3-digit area code + 8-digit phone number, all connected by a "-" (dash), by declaring the DSL map like: The phone number is {number:\d{2}-\d{3}-\d{8}} Any valid java regexp may be used in the variable mask.

fireUntilHalt()

Drools now supports "fireUntilHalt()" feature, that starts the engine in a reactive mode, where rules will be continually fired, until a halt() call is made. This is specially useful for CEP scenarios that require what is commonly known as "active queries".

Rule Base partitioning and multi-thread propagation

Drools ReteOO algorithm now supports an option to start the rule base in a multi-thread mode, where Drools ReteOO network is split into multiple partitions and rules are then evaluated concurrently by multiple threads. This is also a requirement for CEP where there usually are several independent rules running concurrently, with near realtime performance/throughput requirements and the evaluation of one can not interfere with the evaluation of others.

XSD Model Support

Drools now supports XSD models. Remember though the XSD model is generated as pojos local to the Drools classloader. A helper class is there to assist in the creation of the model in the packagebuilder. Once the data model is generated you'll typically use the JAXB dataloader to insert data.

Data Loaders

Drools now supports two data loaders, Smooks and JAXB. Smooks is an open source data transformation tool for ETL and JAXB a standard sun data mapping tool. Unit tests showing Smooks can be found here and JAXB here.

Type safe configuration

In addition to the ability of configuring options in drools through configuration files, system properties and by setting properties through the API setProperty() method, Drools-API now supports type safe configuration. We didn't want to add specific methods for each possible configuration methods for two reasons: it polutes the API and every time a new option is added to Drools, the API would have to change. This way, we followed a modular, class based configuration, where a new Option class is added to the API for each possible configuration, keeping the API stable, but flexible at the same time. So, in order to set configuration options now, you just need to use the enumerations or factories provided for each option. For instance, if you want to configure the knowledge base for assert behavior "equality" and to automatically remove identities from pattern matchings, you would just use the enums:

Example 2.12. Configuring

KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( AssertBehaviorOption.EQUALITY );
config.setOption( RemoveIdentitiesOption.YES );


For options that don't have a predefined constant or can assume multiple values, a factory method is provided. For instance, to configure the alpha threshold to 5, just use the "get" factory method:

Example 2.13. Configuring alpha threshold

config.setOption( AlphaThresholdOption.get(5) );


As you can see, the same setOption() method is used for the different possible configurations, but they are still type safe.

New accumulate functions: collectSet and collectList

There are times when it is necessary to collect sets or lists of values that are derived from the facts attributes, but are not facts themselves. In such cases, it was not possible to use the collect CE. So, Drools now has two accumulate functions for such cases: collectSet for collecting sets of values (i.e., with no duplicate values) and collectList for collecting lists of values (i.e., allowing duplicate values):

Example 2.14. New accumulate functions

# collect the set of unique names in the working memory
$names : Set() from accumulate( Person( $n : name, $s : surname ),
                        collectSet( $n + " " + $s ) )

# collect the list of alarm codes from the alarms in the working memory
$codes : List() from accumulate( Alarm( $c : code, $s : severity ),
                         collectList( $c + $s ) )


New metadata for type declarations: @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 2.15. @propertyChangeSupport

declare Person
	@propertyChangeSupport
end


Batch Executor

Batch Executor allows for the scripting of of a Knowledge session using Commands, which can also re, both the StatelessKnowledgeSession and StatefulKnowledgeSession implement this interface Commands are created using the CommandFactory and executed using the "execute" method, such as the following insert Command:

Example 2.16. Using CommandFactory

ksession.execute( CommandFactory.newInsert( person ) ); 


Typically though you will want to execute a batch of commands, this can be achieved via the composite Command BatchExecution. BatchExecutionResults is now used to handle the results, some commands can specify "out" identifiers which it used to add the result to the BatchExecutionResult. Handily querries can now be executed and results added to the BatchExecutionResult. Further to this results are scoped to this execute call and return via the BatchExecutionResults:

Example 2.17. Using BatchExecutionResult

List<Command> cmds = new ArrayList<Command>();
cmds.add( CommandFactory.newSetGlobal( "list1", new ArrayList(), true ) );
cmds.add( CommandFactory.newInsert( new Person( "jon", 102 ), "person" ) );
cmds.add( CommandFactory.newQuery( "Get People" "getPeople" );

BatchExecutionResults results = ksession.execute( CommandFactory.newBatchExecution( cmds ) );
results.getValue( "list1" ); // returns the ArrayList
results.getValue( "person" ); // returns the inserted fact Person
results.getValue( "Get People" );// returns the query as a QueryResults instance.
end


The CommandFactory details the supported commands, all of which can marshalled using XStream and the BatchExecutionHelper. This can be combined with the pipeline to automate the scripting of a session.

Example 2.18. Using PipelineFactory

Action executeResultHandler = PipelineFactory.newExecuteResultHandler();
Action assignResult = PipelineFactory.newAssignObjectAsResult();
assignResult.setReceiver( executeResultHandler );
Transformer outTransformer = PipelineFactory.newXStreamToXmlTransformer( BatchExecutionHelper.newXStreamMarshaller() );
outTransformer.setReceiver( assignResult );
KnowledgeRuntimeCommand batchExecution = PipelineFactory.newBatchExecutor();
batchExecution.setReceiver( outTransformer );
Transformer inTransformer = PipelineFactory.newXStreamFromXmlTransformer( BatchExecutionHelper.newXStreamMarshaller() );
inTransformer.setReceiver( batchExecution );
Pipeline pipeline = PipelineFactory.newStatelessKnowledgeSessionPipeline( ksession );
pipeline.setReceiver( inTransformer ); 


Using the above for a rulset that updates the price of a Cheese fact, given the following xml to insert a Cheese instance using an out-identifier:

Example 2.19. Updating Cheese fact

<batch-execution>
<insert out-identifier='outStilton'>
  <org.drools.Cheese>
    <type>stilton</type>
    <price>25</price>
    <oldPrice>0</oldPrice>
  </org.drools.Cheese>
</insert>
</batch-execution>


We then get the following BatchExecutionResults:

Example 2.20. Updating Cheese fact

<batch-execution-results>
 <result identifier='outStilton'>
   <org.drools.Cheese>
     <type>stilton</type>
     <oldPrice>0</oldPrice>       
     <price>30</price>
   </org.drools.Cheese>
 </result>
</batch-execution-results>


Marshalling

The MarshallerFactory is used to marshal and unmarshal StatefulKnowledgeSessions. At the simplest it can be used as follows:

Example 2.21. Using MarshallerFactory

// ksession is the StatefulKnowledgeSession
// kbase is the KnowledgeBase
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Marshaller marshaller = MarshallerFactory.newMarshaller( kbase );
marshaller.marshall( baos, ksession );
baos.close();


However with marshalling you need more flexibility when dealing with referenced user data. To achieve this we have the ObjectMarshallingStrategy interface. Two implementations are provided, but the user can implement their own. The two supplied are IdentityMarshallingStrategy and SerializeMarshallingStrategy. SerializeMarshallingStrategy is the default, as used in the example above and it just calls the Serializable or Externalizable methods on a user instance. IdentityMarshallingStrategy instead creates an int id for each user object and stores them in a Map the id is written to the stream. When unmarshalling it simply looks to the IdentityMarshallingStrategy map to retrieve the instance. This means that if you use the IdentityMarshallingStrategy it's stateful for the life of the Marshaller instance and will create ids and keep references to all objects that it attempts to marshal.

Example 2.22. Code to use a IdentityMarshallingStrategy

ByteArrayOutputStream baos = new ByteArrayOutputStream();
Marshaller marshaller = MarshallerFactory.newMarshaller( kbase, new ObjectMarshallingStrategy[] { MarshallerFactory.newIdentityMarshallingStrategy() } );
marshaller.marshall( baos, ksession );
baos.close(); 


For added flexability we can't assume that a single strategy is suitable for this we have added the ObjectMarshallingStrategyAcceptor interface that each ObjectMarshallingStrategy has. The Marshaller has a chain of strategies and when it attempts to read or write a user object it iterates the strategies asking if they accept responsability for marshalling the user object. One one implementation is provided the ClassFilterAcceptor. This allows strings and wild cards to be used to match class names. The default is "*.*", so in the above the IdentityMarshallingStrategy is used which has a default "*.*" acceptor. But lets say we want to serialise all classes except for one given package, where we will use identity lookup, we could do the following:

Example 2.23. Using identity lookup

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectMarshallingStrategyAcceptor identityAceceptor = MarshallerFactory.newClassFilterAcceptor( new String[] { "org.domain.pkg1.*" } );
ObjectMarshallingStrategy identityStratetgy = MarshallerFactory.newIdentityMarshallingStrategy( identityAceceptor );
Marshaller marshaller = MarshallerFactory.newMarshaller( kbase, new ObjectMarshallingStrategy[] { identityStratetgy, MarshallerFactory.newSerializeMarshallingStrategy() } );
marshaller.marshall( baos, ksession );
baos.close();


Knowledge Agent

The KnowlegeAgent is created by the KnowlegeAgentFactory. The KnowlegeAgent provides automatic loading, caching and re-loading, of resources and is configured from a properties files. The KnowledgeAgent can update or rebuild this KnowlegeBase as the resources it uses are changed. The strategy for this is determined by the configuration given to the factory, but it is typically pull based using regular polling. We hope to add push based updates and rebuilds in future versions. The Following example constructs an agent that will build a new KnowledgeBase from the files specified in the path String. It will poll those files every 30 seconds to see if they are updated. If new files are found it will construct a new KnowledgeBase, instead of updating the existing one, due to the "newInstance" set to "true" (however currently only the value of "true" is supported and is hard coded into the engine):

Example 2.24. Constructing an agent

// Set the interval on the ResourceChangeScannerService if you are to use it and default of 60s is not desirable.
ResourceChangeScannerConfiguration sconf = ResourceFactory.getResourceChangeScannerService().newResourceChangeScannerConfiguration();
sconf.setProperty( "drools.resource.scanner.interval",
                  "30" ); // set the disk scanning interval to 30s, default is 60s
ResourceFactory.getResourceChangeScannerService().configure( sconf );
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
aconf.setProperty( "drools.agent.scanDirectories",
                  "true" ); // we want to scan directories, not just files, turning this on turns on file scanning
aconf.setProperty( "drools.agent.newInstance",
                  "true" ); // resource changes results in a new instance of the KnowledgeBase being built,
                            // this cannot currently be set to false for incremental building
    
KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "test agent", // the name of the agent
                                                                kbase, // the KnowledgeBase to use, the Agent will also monitor any exist knowledge definitions
                                                                aconf );
kagent.applyChangeSet( ResourceFactory.newUrlResource( url ) ); // resource to the change-set xml for the resources to add


KnowledgeAgents can take a empty KnowledgeBase or a populated one. If a populated KnowledgeBase is provided, the KnowledgeAgent will iterate KnowledgeBase and subscribe to the Resource that it finds. While it is possible for the KnowledgeBuilder to build all resources found in a directory, that information is lost by the KnowledgeBuilder so those directories will not be continuously scanned. Only directories specified as part of the applyChangeSet(Resource) method are monitored.

Drools Flow

Drools 4.0 had simple "RuleFlow" which was for orchestrating rules. Drools 5.0 introduces a powerful (extensible) workflow engine. It allows users to specify their business logic using both rules and processes (where powerful interaction between processes and rules is possible) and offers a unified enviroment.

Process Instance view at a specific breakpoint

Figure 2.7. Rule Flow properties

Rule Flow properties


Figure 2.8. Current active nodes in a workflow in a specific breakpoint

Current active nodes in a workflow in a specific breakpoint


New Nodes

Timers:

A timer node can be added which causes the execution of the node to wait for a specific period. Currently just uses JDK defaults of initial delay and repeat delay, more complex timers will be available in further milestones.

Human Task:

Processes can include tasks that need to be executed by human actors. Human tasks include parameters like taskname, priority, description, actorId, etc. The process engine can easily be integrated with existing human task component (like for example a WS-HumanTask implementation) using our pluggable work items (see below). Swimlanes and assignment rules are also supported.

The palette in the screenshot shows the two new components, and the workflow itself shows the human task in use. It also shows two "work items" which is explained in the next section:

Figure 2.9. Human task

Human task


Domain Specific Work Items

Domain Specific Work Items are pluggable nodes that users create to facilitate custom task execution. They provide an api to specify a new icon in the palette and gui editor for the tasks properties, if no editor gui is supplied then it defaults to a text based key value pair form. The api then allows execution behaviour for these work items to be specified. By default the Email and Log work items are provided. The Drools flow Manual has been updated on how to implement these.

The below image shows three different work items in use in a workflow, "Blood Pressure", "BP Medication", "Notify GP":

Figure 2.10. Work items

Work items


This one ows a new "Notification" work item:

Figure 2.11. Notification

Notification


Extensible Process Definition Language (ePDL)

Drools 4.0 used Xstream to store it's content, which was not easily human writeable. Drools 5.0 introduced the ePDL which is a XML specific to our process language, it also allows for domain specific extensions which has been talked about in detail in this blog posting "Drools Extensible Process Definition Language (ePDL) and the Semantic Module Framework (SMF)". An example of the XML language, with a DSL extension in red, is shown below.

Example 2.25. Example of the XML language

<process  name="process name" id="process name" package-name="org.domain"
xmlns="http://drools.org/drools-4.0/process"
xmlns:mydsl="http://domain/org/mydsl"
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation="http://drools.org/drools-4.0/process drools-processes-4.0.xsd" >
<nodes>
  <start id="0" />

  <action id="1" dialect="java">
      list.add( "action node was here" ); 
  </action>

    <mydsl:logger id="2" type="warn">
        This is my message         
    <mydsl:logger>

  <end id="3" />
</nodes>

<connections>
  <connection from="0 to="1" />
  <connection from="1" to="2" />
  <connection from="2" to="3" />
</connections>

</process>


Pluggable Nodes

The underlying nodes for the framework are completely pluggable making it simple to extend and to implement other execution models. We already have a partial implementation for OSWorkflow and are working with Deigo to complete this to provide a migration path for OSWorkflow users. Other enhancements include exception scopes, the ability to include on-entry and on-exit actions on various node types, integration with our binary persistence mechanism to persist the state of long running processes, etc. Check out the Drools Flow documentation to learn more.

Human tasks

Human task management is very important in the context of processes. While we allow users to plug in any task component they prefer, we have developed a human task management component that supports the entire life cycle of human tasks based on the WS-HumanTask specification.

New functions to the Drools Flow language

  • Event nodes that allow a process to respond to external events

  • Exception handlers and exception handler scopes to handle exceptions that could be thrown

  • A ForEach node allows instantiating a section of your flow multiple times, for each element in a collection

  • Data type support has been extended

  • Timers are integrated with common node types

As a result, new node types and properties have been added to the Drools Flow editor in Eclipse. You can also find examples of these new features in the integration tests (e.g. ProcessExceptionHandlerTest, ProcessTimerTest, etc.).

Work items

Our pluggable work item approach allows you to plug in domain-specific work in your process in a declarative manner. We plan to build a library of common work items and already provide an implementation for sending emails, finding files, archiving, executing system commands, logging and human tasks.

JPA

Improved support for persistence (JPA) and transactions (JTA).

Example 2.26. An example on how to use persistence and transactions in combination with processes

// create a new JPA-based session and specify the JPA entity manager factory
Environment env = KnowledgeBaseFactory.newEnvironment();
env.set( EnvironmentName.ENTITY_MANAGER_FACTORY, Persistence.createEntityManagerFactory( "emf-name" ) );
env.set( EnvironmentName.TRANSACTION_MANAGER, TransactionManagerServices.getTransactionManager() );
        
StatefulKnowledgeSession ksession = JPAKnowledgeService.newStatefulKnowledgeSession( kbase, null, env ); // KnowledgeSessionConfiguration may be null, and a default will be used
int sessionId = ksession.getId();

// if no transaction boundary is specified, the method invocation is executed in a new transaction automatically
ProcessInstance processInstance = ksession.startProcess( "org.drools.test.TestProcess" );

// the users can also specify the transaction boundary themselves
UserTransaction ut = (UserTransaction) new InitialContext().lookup( "java:comp/UserTransaction" );
ut.begin();
ksession.insert( new Person( "John Doe" ) );
ksession.startProcess( "org.drools.test.TestProcess" );
ksession.fireAllRules();
ut.commit();


Variable Injection

Support direct access to process variables in both MVEL and Java in code constraints and actions, so if you have a variable called "person" in your process, you can now describe constraints like:

Example 2.27. Variable injection example

    * [Java code constraint] return person.getAge() > 20;
    * [MVEL action] System.out.println(person.name);


Miscellaneous Enhancements

  • Process instances can now listen for external events by marking the event node property "external" as true. External events are signaled to the engine using session.signalEvent(type, eventData) More information on how to use events inside your processes can be found in the Drools Flow documentation here: https://hudson.jboss.org/hudson/job/drools/lastSuccessfulBuild/artifact/trunk/target/docs/drools-flow/html/ch03.html#d0e917

  • Process instances are now safe for multi-threading (as multiple thread are blocked from working on the same process instance)

  • Process persistence / transaction support has been further improved. Check out the drools-process/drools-process-enterprise project for more information.

  • The human task component has been extended to support all kinds of data for input / output / exceptions during task execution.

    Example 2.28. As a result, the life cycle methods of the task client have been extended to allow content data

              taskClient.addTask(task, contentData, responseHandler)
              taskClient.complete(taskId, userId, outputData,responseHandler)
              taskFail.complete(taskId, userId, outputData,responseHandler)
    
              long contentId = task.getTaskData().getDocumentContentId();
              taskClient.getContent(contentId, responseHandler);
              ContentData content = responseHandler.getContent();


  • It is now possible to migrate old Drools4 RuleFlows (using the xstream format) to Drools5 processes (using readable xml) during compilation. Migration will automatically be performed when adding the RuleFlow to the KnowledgeBase when the following system property is set: drools.ruleflow.port = true

  • The "Transform" work item allows you to easily transform data from one format to another inside processes. The code and an example can be found in the drools-process/drools-workitems directory.

  • Function imports are now also supported inside processes.

  • The history log - that keeps the history of all executed process instances in a database - has been extended so it is now caable of storing more detailed information for one specfic process instance. It is now possible to find out exactly which nodes were triggered during the execution of the process instance.

  • A new type of join has been added, one that will wait until n of its m incoming connections have been completed. This n could either be hardcoded in the process or based on the value of a variable in the process.

  • Improvements have been made to make persistence easier to configure. The persistence approach is based on a command service that makes sure that all the client invocations are executed inside a transaction and that the state is stored in the database after successful execution of the command. While this was already possible in M4 using the commands directly, we have extended this so that people can simply use the normal StatefulKnowledgeSession interface but simply can configure the persistence using configuration files. For more details, check out the chapter on persistence in the Drools Flow documentation.

Drools Fusion

Drools 5.0 brings to the rules world the full power of events processing by supporting a number of CEP features as well as supporting events as first class citizens in the rules engine.

Event Semantics

Events are (from a rules engine perspective) a special type of fact that has a few special characteristics:

  • they are immutable

  • they have strong time-related relationships

  • they may have clear lifecycle windows

  • they may be transparently garbage collected after it's lifecycle window expires

  • they may be time-constrained

  • they may be included in sliding windows for reasoning

Event Declaration

Any fact type can assume an event role, and its corresponding event semantics, by simply declaring the metadata for it.

Example 2.29. Both existing and generated beans support event semantics:

# existing bean assuming an event role
import org.drools.test.StockTick
declare StockTick
  @role( event )
end

# generated bean assuming an event role
declare Alarm
  @role( event )
  type : String
  timestamp : long
end


Entry-Point Stream Listeners

A new key "from entry-point" has been added to allow a pattern in a rule to listen on a stream, which avoids the overhead of having to insert the object into the working memory where it is potentially reasoned over by all rules.

$st : StockTick( company == "ACME", price > 10 ) from entry-point "stock stream"

Example 2.30. To insert facts into an entry point

WorkingMemoryEntryPoint entry = wm.getWorkingMemoryEntryPoint( "stock stream" );
entry.insert( ticker );


StreamTest shows a unit for this.

Event Correlation and New Operators

Event correlation and time based constraint support are requirements of event processing, and are completely supported by Drools 5.0. The new, out of the box, time constraint operators can be seen in these test case rules: test_CEP_TimeRelationalOperators.drl

As seen in the test above, Drools supports both: primitive events, that are point in time occurrences with no duration, and compound events, that are events with distinct start and end timestamps.

The complete list of operators are:

  • coincides

  • before

  • after

  • meets

  • metby

  • overlaps

  • overlappedby

  • during

  • includes

  • starts

  • startedby

  • finishes

  • finishedby

Sliding Time Windows

Drools 5.0 adds support for reasoning over sliding windows of events. For instance:

StockTick( symbol == "RHAT" ) over window:time( 60 )

The above example will only pattern match the RHAT stock ticks that happened in the last 60 clock ticks, discarding any event older than that.

Session Clock

Enabling full event processing capabilities requires the ability to configure and interact with a session clock. Drools adds support for time reasoning and session clock configuration, allowing it to not only run real time event processing but also simulations, what-if scenarios and post-processing audit by replaying a scenario.

Example 2.31. The Clock is specified as part of the SessionConfiguration, a new class that is optionally specified at session creation time

SessionConfiguration conf = new SessionConfiguration();
conf.setClockType( ClockType.PSEUDO_CLOCK );
StatefulSession session = ruleBase.newStatefulSession( conf );


Event Garbage Collection

Since events usually have strong temporal relationships, it is possible to infer a logical time window when events can possibly match. The engine uses that capability to calculate when an event is no longer capable of matching any rule anymore and automatically retracts that event.

Time Units Support

Drools adopted a simplified syntax for time units, based on the ISO 8601 syntax for durations. This allows users to easily add temporal constraints to the rules writing time in well known units. Example:

SomeEvent( this after[1m,1h30m] $anotherEvent )

The above pattern will match if SomeEvent happens between 1 minute (1m) and 1 hour and 30 minutes after $anotherEvent.

Support to event expiration policy

added the ability to define a per-type event expiration policy. In the example bellow, the StockTick events will expire 10 minutes after they enter the system:

declare StockTick @role( event ) @expires( 10m ) end

Support to temporal operations over arbitrary dates.

Example 2.32. added the ability for point-in-time operators (before, after and coincides) to be used with any arbitrary date field

rule "Allow access"
when
WorkHours( $s : start, $e : end )
LogIn( time after $s, time before $e )
then
// allow access
end


Eclipse IDE

  • Support multiple runtimes: The IDE now supports multiple runtimes. A Drools runtime is a collection of jars on your file system that represent one specific release of the Drools project jars. To create a runtime, you must either point the IDE to the release of your choice, or you can simply create a new runtime on your file system from the jars included in the Drools Eclipse plugin. Drools runtimes can be configured by opening up the Eclipse preferences and selecting the Drools -> Installed Drools Runtimes category, as shown below.

    Figure 2.12. Run times

    Run times


  • Debugging of rules using the MVEL dialect has been fixed

  • Drools Flow Editor

    • Process Skins allow you to define how the different RuleFlow nodes are visualized. We now support two skins: the default one which existed before and a BPMN skin that visualizes the nodes using a BPMN-like representation: http://blog.athico.com/2008/10/drools-flow-and-bpmn.html

    • An (X)OR split now shows the name of the constraint as the connection label

    • Custom work item editors now signal the process correctly that it has been changed