Drools JBPM Introduction
Drools JBPM Introduction
Drools JBPM Introduction
Version 5.4.0.CR1
by The JBoss Drools team [http://www.jboss.org/drools/team.html]
......................................................................................................................................... v 1. Welcome ...................................................................................................................... 1 2. Installation and Setup (Core and IDE) ......................................................................... 3 2.1. Installing and using ............................................................................................. 3 2.1.1. Dependencies and jars ............................................................................. 3 2.1.2. Runtime ................................................................................................... 4 2.1.3. Installing IDE (Rule Workbench) ............................................................... 4 2.2. Building from source ......................................................................................... 12 2.2.1. Getting the sources ................................................................................ 12 2.2.2. Building the sources ............................................................................... 12 2.3. Eclipse ............................................................................................................. 13 2.3.1. Importing Eclipse Projects ....................................................................... 13 3. Getting Involved ........................................................................................................ 21 3.1. Sign up to jboss.org .......................................................................................... 21 3.2. Sign the Contributor Agreement ......................................................................... 21 3.3. Submitting issues via JIRA ................................................................................ 22 3.4. Fork Github ...................................................................................................... 23 3.5. Writing Tests .................................................................................................... 23 3.6. Commit with Correct Conventions ...................................................................... 25 3.7. Submit Pull Requests ........................................................................................ 26 4. Drools Release Notes ................................................................................................ 29 4.1. What is New and Noteworthy in Drools 5.4.0.CR1 ............................................... 29 4.1.1. Drools Expert ......................................................................................... 29 4.1.2. Guvnor .................................................................................................. 35 4.1.3. Planner .................................................................................................. 42 4.2. What is New and Noteworthy in Drools 5.4.0.Beta2 ............................................. 46 4.2.1. Drools Expert ......................................................................................... 46 4.2.2. Drools Fusion ........................................................................................ 49 4.2.3. Guvnor .................................................................................................. 50 4.2.4. Planner .................................................................................................. 55 4.3. What is New and Noteworthy in Drools 5.4.0.Beta1 ............................................. 56 4.3.1. Drools Expert ......................................................................................... 56 4.3.2. Guvnor .................................................................................................. 63 4.3.3. Planner .................................................................................................. 74 4.3.4. Eclipse plugin ........................................................................................ 74 4.4. What is New and Noteworthy in Drools 5.3.0 ...................................................... 75 4.4.1. Drools Expert ......................................................................................... 75 4.4.2. Guvnor .................................................................................................. 78 4.4.3. Drools Planner ....................................................................................... 91 4.4.4. Drools Integration ................................................................................... 93 4.5. What is New and Noteworthy in Drools 5.2.0 ...................................................... 94 4.5.1. Knowledge API (renamed from Drools API) ............................................. 94 4.5.2. Drools Expert and Fusion ....................................................................... 94 4.5.3. Drools and jBPM integration .................................................................. 101
iii
4.5.4. Merging Drools Flow into jBPM5 ........................................................... 102 4.5.5. Guvnor ................................................................................................ 102 4.5.6. Eclipse ................................................................................................. 4.5.7. Maven artifactId changes ...................................................................... 4.6. What is New and Noteworthy in Drools 5.1.0 .................................................... 4.6.1. Drools API ........................................................................................... 4.6.2. Core .................................................................................................... 4.6.3. Expert .................................................................................................. 4.6.4. Flow .................................................................................................... 4.6.5. Guvnor ................................................................................................ 4.6.6. Eclipse ................................................................................................. 4.6.7. Known Issues ...................................................................................... 4.7. What is New and Noteworthy in Drools 5.0.0 .................................................... 4.7.1. Drools API ........................................................................................... 4.7.2. Drools Guvnor ...................................................................................... 4.7.3. Drools Expert ....................................................................................... 4.7.4. Drools Flow .......................................................................................... 4.7.5. Drools Fusion ....................................................................................... 4.7.6. Eclipse IDE .......................................................................................... 4.8. What is new in Drools 4.0 ............................................................................... 4.8.1. Language Expressiveness Enhancements ............................................. 4.8.2. Core Engine Enhancements .................................................................. 4.8.3. IDE Enhancements ............................................................................... 4.8.4. Business Rules Management System - BRMS ....................................... 4.8.5. Miscellaneous Enhancements ............................................................... 4.9. Upgrade tips from Drools 3.0.x to Drools 4.0.x .................................................. 4.9.1. API changes ........................................................................................ 4.9.2. Rule Language Changes ...................................................................... 4.9.3. Drools Update Tool .............................................................................. 4.9.4. DSL Grammars in Drools 4.0 ................................................................ 4.9.5. Rule flow Update for 4.0.2 .................................................................... 5. Drools compatibility matrix ...................................................................................... 113 113 114 114 115 121 124 125 139 140 140 140 143 148 156 164 167 168 169 169 170 170 170 170 170 171 172 173 173 175
iv
vi
Chapter 1.
Chapter 1. Welcome
I've always stated that end business users struggle understanding the differences between rules and processes, and more recently rules and event processing. For them they have this problem in their mind and they just want to model it using some software. The traditional way of using two vendor offerings forces the business user to work with a process oriented or rules oriented approach which just gets in the way, often with great confusion over which tool they should be using to model which bit. PegaSystems and Microsoft have done a great job of showing that the two can be combined and a behavioural modelling approach can be used. This allows the business user to work more naturally where the full range of approaches is available to them, without the tools getting in the way. From being process oriented to rule oriented or shades of grey in the middle - whatever suites the problem being modelled at that time. Drools 5.0 takes this one step further by not only adding BPMN2 based workflow with Drools Flow but also adding event processing with Drools Fusion, creating a more holistic approach to software development. Where the term holistic is used for emphasizing the importance of the whole and the interdependence of its parts. Drools 5.0 is now split into 5 modules, each with their own manual - Guvnor (BRMS/BPMS), Expert (Rules), Fusion (CEP), Flow (Process/Workflow) and Planner. Guvnor is our web based governance system, traditionally referred to in the rules world as a BRMS. We decided to move away from the BRMS term to a play on governance as it's not rules specific. Expert is the traditional rules engine. Fusion is the event processing side, it's a play on data/sensor fusion terminology. Flow is our workflow module, Kris Verlaenen leads this and has done some amazing work; he's currently moving flow to be incorporated into jBPM 5. The fith module called Planner, authored by Geoffrey De Smet, solves allocation and scheduling type problem and while still in the early stage of development is showing a lot of promise. We hope to add Semantics for 2011, based around description logc, and that is being work on as part of the next generaion Drools designs. I've been working in the rules field now for around 7 years and I finally feel like I'm getting to grips with things and ideas are starting to gel and the real innovation is starting to happen. To me It feels like we actually know what we are doing now, compared to the past where there was a lot of wild guessing and exploration. I've been working hard on the next generation Drools Expert design document with Edson Tirelli and Davide Sottara. I invite you to read the document and get involved, http://community.jboss.org/wiki/DroolsLanguageEnhancements. The document takes things to the next level pushing Drools forward as a hybrid engine, not just a capable production rule system, but also melding in logic programming (prolog) with functional programming and description logic along with a host of other ideas for a more expressive and modern feeling language. I hope you can feel the passion that my team and I have while working on Drools, and that some of it rubs off on you during your adventures.
Chapter 1. Welcome
Chapter 2.
drools-jsr94.jar - this is the JSR-94 compliant implementation, this is essentially a layer over the drools-compiler component. Note that due to the nature of the JSR-94 specification, not all features are easily exposed via this interface. In some cases, it will be easier to go direct to the Drools API, but in some environments the JSR-94 is mandated. drools-decisiontables.jar - this is the decision tables 'compiler' component, which uses the drools-compiler component. This supports both excel and CSV input formats. There are quite a few other dependencies which the above components require, most of which are for the drools-compiler, drools-jsr94 or drools-decisiontables module. Some key ones to note are "POI" which provides the spreadsheet parsing ability, and "antlr" which provides the parsing for the rule language itself. NOTE: if you are using Drools in J2EE or servlet containers and you come across classpath issues with "JDT", then you can switch to the janino compiler. Set the system property "drools.compiler": For example: -Ddrools.compiler=JANINO. For up to date info on dependencies in a release, consult the released poms, which can be found on the maven repository.
2.1.2. Runtime
The "runtime" requirements mentioned here are if you are deploying rules as their binary form (either as KnowledgePackage objects, or KnowledgeBase objects etc). This is an optional feature that allows you to keep your runtime very light. You may use drools-compiler to produce rule packages "out of process", and then deploy them to a runtime system. This runtime system only requires drools-core.jar and knowledge-api for execution. This is an optional deployment pattern, and many people do not need to "trim" their application this much, but it is an ideal option for certain environments.
Open the Help->Software updates...->Available Software->Add Site... from the help menu. Location is:
http://download.eclipse.org/tools/gef/updates/releases/
Press next, and agree to install the plug-in (an Eclipse restart may be required). Once this is completed, then you can continue on installing the rules plug-in.
To define a new Drools runtime, click on the add button. A dialog as shown below should pop up, requiring the name for your runtime and the location on your file system where it can be found.
1. If you simply want to use the default jars as included in the Drools Eclipse plugin, you can create a new Drools runtime automatically by clicking the "Create a new Drools 5 runtime ..." button. A file browser will show up, asking you to select the folder on your file system where you want this runtime to be created. The plugin will then automatically copy all required dependencies to the specified folder. After selecting this folder, the dialog should look like the figure shown below. 2. If you want to use one specific release of the Drools project, you should create a folder on your file system that contains all the necessary Drools libraries and dependencies. Instead of creating a new Drools runtime as explained above, give your runtime a name and select the location of this folder containing all the required jars.
After clicking the OK button, the runtime should show up in your table of installed Drools runtimes, as shown below. Click on checkbox in front of the newly created runtime to make it the default Drools runtime. The default Drools runtime will be used as the runtime of all your Drools project that have not selected a project-specific runtime.
You can add as many Drools runtimes as you need. For example, the screenshot below shows a configuration where three runtimes have been defined: a Drools 4.0.7 runtime, a Drools 5.0.0
runtime and a Drools 5.0.0.SNAPSHOT runtime. The Drools 5.0.0 runtime is selected as the default one.
Note that you will need to restart Eclipse if you changed the default runtime and you want to make sure that all the projects that are using the default runtime update their classpath accordingly.
10
You can change the runtime of a Drools project at any time by opening the project properties (right-click the project and select Properties) and selecting the Drools category, as shown below. Check the "Enable project specific settings" checkbox and select the appropriate runtime from the drop-down box. If you click the "Configure workspace settings ..." link, the workspace preferences showing the currently installed Drools runtimes will be opened, so you can add new runtimes there. If you deselect the "Enable project specific settings" checkbox, it will use the default runtime as defined in your global preferences.
11
https://github.com/droolsjbpm Git allows you to fork our code, independently make personal changes on it, yet still merge in our latest changes regularly and optionally share your changes with us. To learn more about git, read the free book Git Pro [http://progit.org/book/].
12
Eclipse
$ git clone git@github.com:droolsjbpm/guvnor.git ... $ cd guvnor $ mvn clean install -DskipTests -Dfull ...
However, there are a lot potential pitfalls, so if you're serious about building from source and possibly contributing to the project, follow the instructions in the README file in droolsjbpmbuild-bootstrap [https://github.com/droolsjbpm/droolsjbpm-build-bootstrap/blob/master/ README.md].
2.3. Eclipse
2.3.1. Importing Eclipse Projects
With the Eclipse project files generated they can now be imported into Eclipse. When starting Eclipse open the workspace in the root of your subversion checkout.
13
14
15
When calling mvn install all the project dependencies were downloaded and added to the local Maven repository. Eclipse cannot find those dependencies unless you tell it where that repository is. To do this setup an M2_REPO classpath variable.
16
17
18
19
20
Chapter 3.
21
22
Fork Github
23
then using a String is not practical so then by all means place them in separate drl files instead to be loaded from the classpath. If your tests need to use a model, please try to use those that already exist for other unit tests; such as Person, Cheese or Order. If no classes exist that have the fields you need, try and update fields of existing classes before adding a new class. There are a vast number of tests to look over to get an idea, MiscTest is a good place to start. https://github.com/droolsjbpm/drools/blob/master/drools-compiler/src/test/java/org/drools/ integrationtests/MiscTest.java [https://github.com/droolsjbpm]
24
25
related to this commit. Use an additional new line and dash for each separate point you wish to make. You may add additional JIRA cross references to the same commit, if it's appropriate. In general try to avoid combining unrelated issues in the same commit. Don't forget to rebase your local fork from the original master and then push your commits back to your fork.
26
The pull request then goes into a queue for everyone to see and comment on. Below you can see a typical pull request. The pull requests allow for discussions and it shows all associated commits and the diffs for each commit. The discussions typically involve code reviews which provide helpful suggestions for improvements, and allows for us to leave inline comments on specific parts of the code. Don't be disheartened if we don't merge straight away, it can often take several revisions before we accept a pull request. Luckily github makes it very trivial to go back to your code, do some more commits and then update your pull request to your latest and greatest. It can take time for us to get round to responding to pull requests, so please be patient. Submitted tests that come with a fix will generally be applied quite quickly, where as just tests will often way until we get time to also submit that with a fix. Don't forget to rebase and resubmit your request from time to time, otherwise over time it will have merge conflicts and core developers will general ignore those.
27
28
Chapter 4.
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kbuilder.batch() .add(ResourceFactory.newByteArrayResource(rules1.getBytes()), ResourceType.DRL) .add(ResourceFactory.newByteArrayResource(rules2.getBytes()), ResourceType.DRL) .add(ResourceFactory.newByteArrayResource(declarations.getBytes()), ResourceType.DRL) .build();
In this way it is no longer necessary to build the DRLs files in the right order (e.g. first the DRLs containing the type declarations and then the ones with the rules using them) and it will also be possible to have circular references among them. Moreover the KnowledgeBuilder (regardless if you are using the batch mode or not) also allows to discard what has been added with the last DRL(s) building. This can be useful to recover from having added a wrong DRL to the KnowledgeBuilder as it follows:
29
@PropertyReactive public static class Person { private String firstName; private String lastName; }
In this way, for instance, if you have a rule like the following:
rule "Every person named Mario is a male" when $person : Person( firstName == "Mario" ) then modify ( $person ) { setMale( true ) }
30
Drools Expert
end
you won't have to add the no-loop attribute to it in order to avoid an infinite recursion because the engine recognizes that the pattern matching is done on the 'firstName' property while the RHS of the rule modifies the 'male' one. Note that this feature does not work for update(), and this is one of the reasons why we promote modify() since it encapsulates the field changes within the statement. Moreover, on Java classes, you can also annotate any method to say that its invocation actually modifies other properties. For instance in the former Person class you could have a method like:
@Modifies( { "firstName", "lastName" } ) public void setName(String name) { String[] names = name.split("\\s"); this.firstName = names[0]; this.lastName = names[1]; }
it will correctly recognize that the values of both properties 'firstName' and 'lastName' could have potentially been modified and act accordingly, not missing of reevaluating the patterns constrained on them. At the moment the usage of @Modifies is not allowed on fields but only on methods. This is coherent with the most common scenario where the @Modifies will be used for methods that are not related with a class field as in the Person.setName() in the former example. Also note that @Modifies is not transitive, meaning that if another method internally invokes the Person.setName() one it won't be enough to annotate it with @Modifies( { "name" } ), but it is necessary to use @Modifies( { "firstName", "lastName" } ) even on it. Very likely @Modifies transitivity will be implemented in the next release. For what regards nested accessors, the engine will be notified only for top level fields. In other words a pattern matching like:
will be revaluated only for modification of the 'address' property of a Person object. In the same way the constraints analysis is currently strictly limited to what there is inside a pattern. Another example could help to clarify this. An LHS like the following:
$p : Person( )
31
will not listen on modifications of the person's name, while this one will do:
Indeed, annotating a pattern with @watch allows you to modify the inferred set of properties for which that pattern will react. Note that the properties named in the @watch annotation are actually added to the ones automatically inferred, but it is also possible to explicitly exclude one or more of them prepending their name with a ! and to make the pattern to listen for all or none of the properties of the type used in the pattern respectively with the wildcrds * and !*. So, for example, you can annotate a pattern in the LHS of a rule like:
// listens for changes on both firstName (inferred) and lastName Person( firstName == $expectedFirstName ) @watch( lastName ) // listens for all the properties of the Person bean Person( firstName == $expectedFirstName ) @watch( * ) // listens for changes on lastName and explicitly exclude firstName Person( firstName == $expectedFirstName ) @watch( lastName, !firstName ) // listens for changes on all the properties except the age one Person( firstName == $expectedFirstName ) @watch( *, !age )
Since doesn't make sense to use this annotation on a pattern using a type not annotated with @PropertyReactive the rule compiler will raise a compilation error if you try to do so. Also the duplicated usage of the same property in @watch (for example like in: @watch( firstName, ! firstName ) ) will end up in a compilation error. In a next release we will make the automatic detection of the properties to be listened smarter by doing analysis even outside of the pattern. It also possible to enable this feature by default on all the types of your model or to completely disallow it by using on option of the KnowledgeBuilderConfiguration. In particular this new PropertySpecificOption can have one of the following 3 values:
32
Drools Expert
- DISABLED => the feature is turned off and all the other related annotations are just ignored - ALLOWED => this is the default behavior: types are not property reactive unless they are not annotated with @PropertySpecific - ALWAYS => all types are property reactive by default
So, for example, to have a KnowledgeBuilder generating property reactive types by default you could do:
In this last case it will be possible to disable the property reactivity feature on a specific type by annotating it with @ClassReactive.
Driver john = new Driver("John", "Smith", new LocalDate().minusYears(10)); Car mini = new Car("MINI-01", CarType.SMALL, false, new BigDecimal("10000.00")); PolicyRequest johnMiniPolicyRequest = new PolicyRequest(john, mini); johnMiniPolicyRequest.addCoverageRequest(new CoverageRequest(CoverageType.COLLISION)); johnMiniPolicyRequest.addCoverageRequest(new CoverageRequest(CoverageType.COMPREHENSIVE
simulationFluent .newKnowledgeBuilder() .add(ResourceFactory.newClassPathResource("org/drools/examples/ carinsurance/rule/policyRequestApprovalRules.drl"), ResourceType.DRL) .end() .newKnowledgeBase() .addKnowledgePackages() .end() .newStatefulKnowledgeSession() .insert(john).set("john") .insert(mini).set("mini")
33
You can even test your CEP rules in unit tests without suffering from slow tests:
@Test public void lyingAboutAge() { SimulationFluent simulationFluent = new DefaultSimulationFluent(); Driver realJohn = new Driver("John", "Smith", new LocalDate().minusYears(10)); Car realMini = new Car("MINI-01", CarType.SMALL, false, new BigDecimal("10000.00")); PolicyRequest realJohnMiniPolicyRequest = new PolicyRequest(realJohn, realMini);
Driver fakeJohn = new Driver("John", "Smith", new LocalDate().minusYears(30)); Car fakeMini = new Car("MINI-01", CarType.SMALL, false, new BigDecimal("10000.00")); PolicyRequest fakeJohnMiniPolicyRequest = new PolicyRequest(fakeJohn, fakeMini); fakeJohnMiniPolicyRequest.addCoverageRequest(new CoverageRequest(CoverageType.COLLISION fakeJohnMiniPolicyRequest.addCoverageRequest(new CoverageRequest(CoverageType.COMPREHEN fakeJohnMiniPolicyRequest.setAutomaticallyRejected(false);
simulationFluent .newStep(0) .newKnowledgeBuilder() .add(ResourceFactory.newClassPathResource("org/drools/examples/ carinsurance/cep/policyRequestFraudDetectionRules.drl"), ResourceType.DRL) .end() .newKnowledgeBase() .addKnowledgePackages() .end(World.ROOT, KnowledgeBase.class.getName()) .newStatefulKnowledgeSession() .end() .newStep(1000) .getStatefulKnowledgeSession() .insert(realJohn).set("realJohn") .insert(realMini).set("realMini") .insert(realJohnMiniPolicyRequest).set("realJohnMiniPolicyRequest")
34
Guvnor
.fireAllRules() .test("realJohnMiniPolicyRequest.requiresManualApproval == false") .end() .newStep(5000) .getStatefulKnowledgeSession() .insert(fakeJohn).set("fakeJohn") .insert(fakeMini).set("fakeMini") .insert(fakeJohnMiniPolicyRequest).set("fakeJohnMiniPolicyRequest") .fireAllRules() .test("fakeJohnMiniPolicyRequest.requiresManualApproval == true") .end() .runSimulation(); }
4.1.2. Guvnor
4.1.2.1. BRL editor supports "timer" and "calendar" attributes
Support has been added for the "timer" and "calendar" attributes.
35
36
Guvnor
37
38
Guvnor
Figure 4.6. Dependent enumerations in the Web Guided Decision Table editor
A default value editor is correct for the data-type of the column's Fact\. If a "Value List" is provided, the default value needs to be one of the values in the list.
39
If the column represents a field with an enumeration the default value must be one of the enumeration's members. If the column uses an operator that does not need a value (e.g. "is null") a default value cannot be provided. If the column field is a "dependent enumeration" the default value must be one of the permitted values based upon parent enumeration default values, if any. Default values are not required for Limited Entry tables.
40
Guvnor
Figure 4.8. Setting the default value of a cell with a Value List
41
4.1.3. Planner
4.1.3.1. New example selection screen
42
Planner
4.1.3.5. Chaining support makes it easy to implement TSP and Vehicle Routing
Untill now, implementing TSP or Vehicle Routing like problems in Planner was hard. The new chaining support makes it easy. You simply declare that a planning variable (previousAppearance) of this planning entity (VrpCustomer) is chained and therefor possibly referencing another planning entity (VrpCustomer) itself, creating a chain with that entity.
43
...
@PlanningVariable(chained = true) @ValueRanges({ @ValueRange(type = ValueRangeType.FROM_SOLUTION_PROPERTY, solutionProperty = "vehic @ValueRange(type = ValueRangeType.FROM_SOLUTION_PROPERTY, solutionProperty = "custo excludeUninitializedPlanningEntity = true)}) public VrpAppearance getPreviousAppearance() { return previousAppearance; } ... }
Without any extra boilerplate code, this is compatible with: Every optimization algorithm: including construction heuristics (first fit, first fit decreasing, ...), local search (tabu search, simmulated annealing), ...
44
Planner
The generic build-in move factories. Note: currently there are chained alternatives for each move factory, but those will be unified with the originals soon. Repeated planning, including real-time planning For more information, read the Planner reference manual [http://www.jboss.org/drools/ documentation].
See the CloudBalance example for an implementation. In this way, Planner does not use Drools at all. This allows you to: Use Planner, even if your company forbids any other language than Java (including DRL). Hook Planner up to an existing score calculation system, which you don't want to migrate to DRL at this time. Or just use Java if you prefer that over DRL. Currently, there is only one Java way implemented: SimpleScoreCalculator, which is slow. An IncrementalScoreCalculator will be implemented soon.
45
@PropertySpecific public static class Person { private String firstName; private String lastName; }
Given this simple type declaration, the most evident advantage of this new Property Specific feature, will be, for instance, that the following rule:
rule "Modify last name" when Person( firstName == "Mario" ) then modify($person) { setLastName("Fusco") }
46
Drools Expert
end
will no longer end up in an infinite loop. Moreover on Java classes you can also annotate any method to say that its invocation actually modifies other properties. For instance in the former Person class you could have a method like:
@Modifies( { "firstName", "lastName" } ) public void setName(String name) { String[] names = name.split("\\s"); this.firstName = names[0]; this.lastName = names[1]; }
it will correctly recognize that both the firstName and lastName have been modified and act accordingly. Of course the @Modifies annotation on a method has no effect if the declaring class isn't annotated with @PropertySpecific. The third newly introduced annotation is on patterns and allows you to modify the inferred set of properties "listened" by it. So, for example, you can annotate a pattern in the LHS of a rule like:
Person( firstName == $expectedFirstName ) @watch( lastName ) // --> listens for changes on both firstName (inferred) and lastName Person( firstName == $expectedFirstName ) @watch( * ) // --> listens for all the properties of the Person bean Person( firstName == $expectedFirstName ) @watch( lastName, !firstName ) // --> listens for changes on lastName and explicitly exclude firstName Person( firstName == $expectedFirstName ) @watch( *, !age ) // --> listens for changes on all the properties except the age one
The usage of @watch on a type not annotated as @PropertySpecific will raise a compilation error. The same will happen if you mention an unknown property name inside @watch or use the same name more than once like for example in: @watch( lastName, !lastName )
47
lhsAccumulate := ACCUMULATE LEFT_PAREN lhsAnd (COMMA|SEMICOLON) accumulateFunctionBinding (COMMA accumulateFunctionBinding)* (SEMICOLON constraints)? RIGHT_PAREN SEMICOLON?
E.g.:
rule "Accumulate example" when accumulate( Cheese( $price : price ); $a1 : average( $price ), $m1 : min( $price ), $M1 : max( $price ); // a semicolon, followed by inline constraints $a1 > 10 && $M1 <= 100, // inline constraint $m1 == 5 // inline constraint ) then // do something end
48
Drools Fusion
Example:
Example:
49
Rules can then use the declared window by referencing using a FROM CE. Example:
rule "RHT ticks in the window" when accumulate( StockTick( symbol == "RHT" ) from window Ticks, $cnt : count(1) ) then // there has been $cnt RHT ticks over the last 10 ticks end
4.2.3. Guvnor
4.2.3.1. Guvnor requirements change
Guvnor 5.4.x requires at least Java 6 to run. The Drools and jBPM will still run on Java 5. Guvnor 5.3.x hotfixes will still run on Java 5 too.
50
Guvnor
51
52
Guvnor
Figure 4.13. A decision table with BRL fragments and regular columns
53
54
Planner
{<varName>:CF:<factType.fieldName>}
If you have an active Working-Set defining a Custom Form configuration for factType.fieldName, the Custom Form will be invoked by Rule Editor while setting the value of that variable.
4.2.4. Planner
4.2.4.1. Benchmarker supports custom input and output files
The Benchmarker can now read and write the input and output files from any format, through the ProblemIO interface. The default is still an XStream implementation.
55
rule "Students and Workers" no-loop when $p : Person( $name : name, $age : age < 25, $weight : weight ) then IWorker w = don( $p, IWorker.class, true ); w.setWage( 1200 ); update( w ); IStudent s = don( $p, IStudent.class, true ); s.setSchool( "SomeSchool" ); update( s ); end
rule "Working Students" salience -10 when $s : IStudent( $school : school, $name : name, this isA IWorker, $wage : fields[ "wage" ] ) then System.out.println( $name + " : I have " + $wage + " to pay the fees at " + $school ); end
A two part detailed article has been written up at a blog, which will later be improved and rolled into the main documentation. For now you can read them here.
http://blog.athico.com/2011/12/new-feature-spotlight-traits-part-1.html http://blog.athico.com/2011/12/dynamic-typing-in-rules-traits-part-2.html
56
Drools Expert
57
58
Drools Expert
The Simulator runs the Simulation. The Simulation is your scenario definition. The Simulation consists of 1 to n Paths, you can think of a Path as a sort of Thread. The Path is a chronological line on which Steps are specified at given temporal distances from the start. You don't specify a time unit for the Step, say 12:00am, instead it is always a relative time distance from the start of the Simulation (note: in Beta2 this will be relative time distance from the last step in the same path). Each Step contains one or more Commands, i.e. create a StatefulKnowledgeSession or insert an object or start a process. These are the very same commands that you would use to script a knowledge session using the batch execution, so it's re-using existing concepts. 1.1 Simulation 1..n Paths 1..n Steps 1..n Commands All the steps, from all paths, are added to a priority queue which is ordered by the temporal distance, and allows us to incrementally execute the engine using a time slicing approach. The simulator pops of the steps from the queue in turn. For each Step it increments the engine clock and then executes all the Step's Commands. Here is an example Command (notice it uses the same Commands as used by the CommandExecutor):
Commands can be grouped together, especially Assertion commands, via test groups. The test groups are mapped to JUnit "test methods", so as they pass or fail using a specialised JUnit Runner the Eclipse GUI is updated - as illustrated in the above image, showing two passed test groups named "test1" and "test2". Using the JUnit integration is trivial. Just annotate the class with @RunWith(JUnitSimulationRunner.class). Then any method that is annotated with @Test and returns a Simulation instance will be invoked executing the returned Simulation instance in the Simulator. As test groups are executed the JUnit GUI is updated. When executing any commands on a KnowledgeBuilder, KnowledgeBase or StatefulKnowledgeSession the system assumes a "register" approach. To get a feel for this look at the org.drools.simulation.impl.SimulationTest [https://github.com/droolsjbpm/droolsjbpm-integration/ blob/8100e28668537aa5fe04ce5dd0a62f3dc779b30f/drools-simulator/src/test/java/org/drools/ simulation/impl/SimulationTest.java] at github (path may change over time).
59
cmds.add( new SetVariableCommandFromLastReturn( "path1", KnowledgeBuilder.class.getName() ) ); cmds.add( new KnowledgeBuilderAddCommand( ResourceFactory.newByteArrayResource( str.getBytes() ), ResourceType.DRL, null ) );
Notice the set command. "path1" is the context, each path has it's own variable context. All paths inherit from a "root" context. "KnowledgeBuilder.class.getName() " is the name that we are setting the return value of the last command. As mentioned before we consider the class names of those classes as registers, any further commands that attempt to operate on a knowledge builder will use what ever is assigned to that, as in the case of KnowledgeBuilderAddCommand. This allows multiple kbuilders, kbases and ksessions to exist in one context under different variable names, but only the one assigned to the register name is the one that is currently executed on. The code below show the rough outline used in SimulationTest:
Simulation simulation = new SimulationImpl(); PathImpl path = new PathImpl( simulation, "path1" ); simulation.getPaths().put( "path1", path ); List<Step> steps = new ArrayList<Step>(); path.setSteps( steps ); List<Command> cmds = new ArrayList<Command>(); .... add commands to step here .... // create a step at temporal distance of 2000ms from start steps.add( new StepImpl( path, cmds, 2000 ) );
We know the above looks quite verbose. SimulationTest just shows our low level canonical model, the idea is that high level representations are built ontop of this. As this is a builder API we are currently focusing on two sets of fluents, compact and standard. We will also work on a spreadsheet UI for building these, and eventually a dedicated textual dsl. The compact fluent is designed to provide the absolute minimum necessary to run against a single ksession. A good place to start is org.drools.simulation.impl.CompactFluentTest [https://github.com/droolsjbpm/droolsjbpmintegration/blob/8100e28668537aa5fe04ce5dd0a62f3dc779b30f/drools-simulator/src/test/java/ org/drools/simulation/impl/CompactFluentTest.java], a snippet of which is shown below. Notice we set "yoda" to "y" and can then assert on that. Currently inside of the test string it executes using mvel. The eventual goal is to build out a set of hamcrest [http://code.google.com/p/hamcrest/] matchers that will allow assertions against the state of the engine, such as what rules have fired and optionally with with data.
60
Drools Expert
FluentCompactSimulation f = new FluentCompactSimulationImpl(); f.newStatefulKnowledgeSession() .getKnowledgeBase() .addKnowledgePackages( ResourceFactory.newByteArrayResource( str.getBytes() ), ResourceType.DRL ) .end() .newStep( 100 ) // increases the time 100ms .insert( new Person( "yoda", 150 ) ).set( "y" ) .fireAllRules() // show testing inside of ksession execution .test( "y.name == 'yoda'" ) .test( "y.age == 160" );
Note that the test is not executing at build time, it's building a script to be executed later. The script underneath matches what you saw in SimulationTest. Currently the way to run a simulation manually is shown below. Atlhough you already saw in SimulationTest that JUnit will execute these automatically. We'll improve this over itme.
SimulationImpl sim = (SimulationImpl) ((FluentCompactSimulationImpl) f).getSimulation(); Simulator simulator = new Simulator( sim, new Date().getTime() ); simulator.run();
The standard fluent is almost a 1 to 1 mapping to the cannonical path, step and command structure in SimulationTest- just more compact. Start by looking in org.drools.simulation.impl.StandardFluentTest [https://github.com/droolsjbpm/droolsjbpmintegration/blob/8100e28668537aa5fe04ce5dd0a62f3dc779b30f/drools-simulator/src/test/java/ org/drools/simulation/impl/StandardFluentTest.java]. This fluent allows you to run any number of paths and steps, along with a lot more control over multiple kbuilders, kbases and ksessions.
FluentStandardSimulation f = new FluentStandardSimulationImpl(); f.newPath("init") .newStep( 0 ) // set to ROOT, as I want paths to share this .newKnowledgeBuilder() .add( ResourceFactory.newByteArrayResource( str.getBytes() ), ResourceType.DRL ) .end(ContextManager.ROOT, KnowledgeBuilder.class.getName() ) .newKnowledgeBase() .addKnowledgePackages() .end(ContextManager.ROOT, KnowledgeBase.class.getName() )
61
.end() .newPath( "path1" ) .newStep( 1000 ) .newStatefulKnowledgeSession() .insert( new Person( "yoda", 150 ) ).set( "y" ) .fireAllRules() .test( "y.name == 'yoda'" ) .test( "y.age == 160" ) .end() .end() .newPath( "path2" ) .newStep( 800 ) .newStatefulKnowledgeSession() .insert( new Person( "darth", 70 ) ).set( "d" ) .fireAllRules() .test( "d.name == 'darth'" ) .test( "d.age == 80" ) .end() .end() .end
There is still an aweful lot to do, this is designed to eventually provide a unified simulation and testing environment for rules, workflow and event processing over time, and eventually also over distributed architectures.
Flesh out the api to support more commands, and also to encompass jBPM commands Improve out of the box usability, including moving interfaces to knowlege-api and hiding "new" constructors with factory methods Commands are already marshallable to json and xml. They should be updated to allow full round tripping from java api commands and json/xml documents. Develop hamcrest matchers for testing state What rule(s) fired, including optionally what data was used with the executing rule (Drools) What rules are active for a given fact What rules activated and de-activated for a given fact change Process variable state (jBPM) Wait node states (jBPM) Design and build tabular authoring tools via spreadsheet, targetting the web with round tripping to excel. Design and develop textual DSL for authoing - maybe part of DRL (long term task).
62
Guvnor
4.3.2. Guvnor
4.3.2.1. Guided Decision Table - Limited Entry
The Guided Decision Table editor and wizard now support the creation of "Limited Entry" tables.
63
64
Guvnor
65
66
Guvnor
67
68
Guvnor
69
Execute a Work Item Set the value of a field on an existing Fact to the value of a Work Item output (result) parameter. Set the value of a field on a new Fact to the value of a Work Item output (result) parameter.
70
Guvnor
Figure 4.32. Setting a field from a Work Item output (result) parameter
71
In the decision table above, row 2 is an impossible match, because there is no Person with a minimum age of 21 and a maximum age of 20.
72
Guvnor
In the decision table above, row 2 and 3 are a conflicting match, because a Person of age 67 will match both rows: it's unclear whether that Person has to pay a fee of 200 or 100.
73
Template Keys in 'free-form' LHS or RHS elements are considered 'Text' (i.e. you'll get a TextBox in the Template data screen). Data-types should be correctly escaped in the 'free-form' entry. For example: System.out.println("@{key}");
4.3.3. Planner
4.3.3.1. Build-in move factories
Planner now comes with 2 build-in move factories: GenericChangeMoveFactory and GenericSwapMoveFactory. Here's an example that uses both of them:
It's no longer required to write your own Move and MoveFactory implementations, but you still can (and mix those in too).
74
kconf );
All matched rule's Activations are inserted into WorkingMemory as facts. So you can now match against an Activation. The rule's metadata and declarations are available as fields on the Activation object. You can use the kcontext.blockActivation( Activation match ) for the current rule to block the selected activation. Only when that rule becomes false will the activation be eligible for firing. If it is already eligible for firing and is later blocked, it will be removed from the agenda until it is unblocked.
75
An activation may have multiple blockers and a count is kept. All blockers must became false for the counter to reach zero to enable the Activation to be eligible for firing. kcontext.unblockAllActivations( $a ) is an over-ride rule that will remove all blockers regardless An activation may also be cancelled, so it never fires with cancelActivation An unblocked Activation is added to the Agenda and obeys normal salience, agenda groups, ruleflow groups etc. @activationListener('direct') allows a rule to fire as soon as it's matched, this is to be used for rules that block/unblock activations, it is not desirable for these rules to have side effects that impact else where. The name may change later, this is actually part of the pluggable terminal node handlers I made, which is an "internal" feature for the moment.
Here is a basic example that will block all activations from rules that have metadata @department('sales'). They will stay blocked until the blockerAllSalesRules rule becomes false, i.e. "go2" is retracted.
rule rule1 @department('sales') when $s : String( this == 'go1' ) then list.add( kcontext.rule.name + ':' + $s ); end rule rule2 @department('sales') when $s : String( this == 'go1' ) then list.add( kcontext.rule.name + ':' + $s ); end rule blockerAllSalesRules @activationListener('direct') when $s : String( this == 'go2' ) $i : Activation( department == 'sales' ) then list.add( $i.rule.name + ':' + $s ); kcontext.blockActivation( $i ); end
76
Drools Expert
This example shows how you can use active property to count the number of active or inactive (already fired) activations.
rule rule1 @department('sales') when $s : String( this == 'go1' ) then list.add( kcontext.rule.name + ':' + $s ); end rule rule2 @department('sales') when $s : String( this == 'go1' ) then list.add( kcontext.rule.name + ':' + $s ); end rule rule3 @department('sales') when $s : String( this == 'go1' ) then list.add( kcontext.rule.name + ':' + $s ); end rule countActivateInActive @activationListener('direct') when $s : String( this == 'go2' ) $active : Number( this == 1 ) from accumulate( $a : Activation( department == 'sales', active == true ), count( $a ) ) $inActive : Number( this == 2 ) from accumulate( $a : Activation( department == 'sales', active == false ), count( $a ) ) then kcontext.halt( ); end
Example use:
77
Example 4.5.
declare entry-point X @doc( "This entry point is receives events from the message queue X" ) end
4.4.1.6.1. IsA
operator
The operator isA can be used in patterns to check whether an object is wearing a trait or not E.g. Worker( this isA Student )
4.4.1.6.3. Usage
To add/remove a trait to an object, in the RHS:
TraitClass traited = don( $object, TraitClass ) Thing stripped = shed( $traitedObject, TraitClass )
4.4.2. Guvnor
4.4.2.1. Declarative type extension
Following the enhancement to Drools Expert type declaration in Guvnor now support 'extends' to inherit from super-classes. Sub-classes can extend either other types declared in the same
78
Guvnor
package or imported Java classes. In order to extend a type declared in Java by a declared subtype, repeat the supertype in a declare statement without any fields.
The view no longer repeats intermediate level sub-package names that are empty (community led effort). The package view can be viewed hierarchically, as has been the default up to 5.2.0.Final. The package view can now also be viewed "flat" with no nesting The tree's nodes can be fully expanded or collapsed.
79
80
Guvnor
81
<title>constants.BusinessRuleAssets()</
To emphasis the separation, asset groups have become their own "editor" appearing as a tab in Guvnor's main, central panel.
82
Guvnor
types of asset. The immediate problem with this approach is however that finding different asset types on a "paged table" becomes more cumbersome for the user; as they'd have to sort by type and page through. We therefore ask for community feedback.
Removal of sorting You are now able to restore the original sort order of a column by clicking on the sort icon through: ascending, descending and none. Formulae and Predicates support value lists Up until now only literal value columns could take advantage of value lists; either "Guvnor enums" or the Decision Table's "Optional value list". This been rectified with this release bringing the advantage of predefined choices for these types of fields to the business user.
83
84
Guvnor
85
86
Guvnor
87
88
Guvnor
Figure 4.47. Choose how rows are created - select the columns you want to expand upon
89
90
Drools Planner
91
First Fit First is StartingSolutionInitializer) Fit Decreasing (this how most of the examples implemented their
Best Fit Best Fit Decreasing Future versions will support more construction heuristics.
4.4.3.2. Phasing
Planner can now run several solver phases sequentially: each phase is a different optimization algorithm. For example: run First Fit Decreasing, then Simulated Annealing, then Tabu Search:
<solver> ... <constructionheuristic> ... <!-- First Fit Decreasing --> </constructionheuristic> <localSearch> ... <!-- Simulated Annealing --> </localSearch> <localSearch> ... <!-- Tabu Search --> </localSearch> </solver>
92
Drools Integration
If one of the planning facts change while a planning problem is being solved, Planner can now process such a planning fact change and incrementally continue from the best solution found before that planning fact change. In practice, this means it can find a good solution for a big planning problem only a few milliseconds after a planning fact changes. Planner's documentation now covers several common techniques such as backup planning, continuous planning and real-time planning.
detailed documentation on planning entity and planning variable an optimization algorithms overview guidelines on what's the easiest path to get started Info on common pitfalls and solutions The NQueens examples has been refactored to feel more like a real-world example.
93
drools.dialect.mvel.strict = <true|false>
However there were some places in execution when strict mode was not enforced. Effort has now been done to ensure that type safety is enforced through out, unless "strict == false". This means that some bad code that compiled before may not compile now, because it is not type safe. For those cases where the type safety cannot be achieved at compile time we added the @typesafe annotation, discussed in it's own section.
4.5.1.1.2. Classloader
The Classloader has been improved to use a CompositeClassLoader instead of the previous hierarchical "parent" classloader. This was necessary for OSGi where each module needs it's own classpath, but reflection will not work if classloader cannot be found. Modules now add themselves to the composite classloader when first initialised. This is also exposed to the user where the previous Classloader argument on the kbase and kbuilder configuration now takes vararg of ClassLoaders, all of which are now searchable.
94
rule "Max, min and average" when accumulate( Cheese( $price : price ), $max : max( $price ), $min : min( $price ), $avg : average( $price ) ) then // do something end
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 )
import org.people.Person
95
declare Person end declare Student extends Person school : String end declare LongTermStudent extends Student years : int course : String end
Person( age * 2 > $anotherPersonsAge + 2 ) // mathematical expressions Person( addresses["home"].streetName.startsWith( "High Park" ) ) // method calls and collections simplified syntax Person( isAdult() ) // boolean expression without relational operator
The new parser also support free form expressions on the "from" clause, allowing for instance, new syntaxes, like inline creation for lists:
Cheese( ) from [ $stilton, $brie, $provolone ] // inline list creation and iteration
96
PackageDescr pkg = DescrFactory.newPackage() .name("org.drools.example") .newRule().name("Xyz") .attribute("ruleflow-grou","bla") .lhs() .and() .pattern("Foo").id( false ).constraint("bar==baz").constraint("x>y").end() .not().pattern("Bar").constraint("a+b==c").end().end() .end() .end() .rhs( "System.out.println();" ).end() .getDescr(); "$foo",
The default order is the declared order, but this can be overiden using @Position
declare Cheese name : String @position(1) shop : String @position(2) price : int @position(0) end
The @Position annotation, in the org.drools.definition.type package, can be used to annotate original pojos on the classpath. Currently only fields on classes can be annotated. Inheritence of classes is supported, but not interfaces of methods yet.
97
Example patterns, with two constraints and a binding. Remember semicolon ';' is used to differentiate the positional section from the named argument section. Variables and literals and expressions using just literals are supported in posional arguments, but not variables.
Shop", p; ) Shop"; p : price ) "Cheese Shop", p : price ) shop == "Cheese Shop", p : price )
declare Location thing : String location : String end query isContainedIn( String x, String y ) Location( x := thing, y := location) or ( Location(z := thing, y := location) and ?isContainedIn( x := x, z := y ) ) end
98
location : String end query isContainedIn( String x, String y ) Location(x, y;) or ( Location(z, y;) and ?isContainedIn(x, z;) ) end
Here is an example of query element inside of a rule using mixed positional/named arguments.
package org.drools.test import java.util.List import java.util.ArrayList dialect "mvel" declare Here place : String end declare Door fromLocation : String toLocation : String end declare Location thing : String location : String end declare Edible thing : String end query connect( String x, String y ) Door(x, y;) or Door(y, x;) end query whereFood( ( Location(x, Edible(x;) or ( Location(z, String x, String y ) y;) and ) y;) and
99
whereFood(x, z;) ) end query look(String place, List things, List food, List exits) Here(place;) things := List() from accumulate( Location(thing, place;), collectList( thing ) ) food := List() from accumulate( ?whereFood(thing, place;), collectList( thing ) ) exits := List() from accumulate( ?connect(place, exit;), collectList( exit ) ) end rule reactiveLook when Here( $place : place) ?look($place, $things; $food := food, $exits := exits) then System.out.println( \"You are in the \" + $place); System.out.println( \" You can see \" + $things ); System.out.println( \" You can eat \" + $food ); System.out.println( \" You can go to \" + $exits ); end
As previously mentioned you can use live "open" queries to reactively receive changes over time from the query results, as the underlying data it queries against changes. Notice the "look" rule calls the query without using '?'.
query isContainedIn( String x, String y ) Location(x, y;) or ( Location(z, y;) and isContainedIn(x, z;) ) end rule look when Person( $l : likes ) isContainedIn( $l, 'office'; ) then insertLogical( $l + 'is in the office' ); end
Literal expressions can passed as query arguments, but at this stage you cannot mix expressions with variables. It is possible to call queries from java leaving arguments unspecified using the static field org.drools.runtime.rule.Variable.v - note you must use 'v' and not an alternative instanceof Variable. The following example will return all objects contained in the office.
100
results = ksession.getQueryResults( "isContainedIn", new Object[] { Variable.v, "office" } ); l = new ArrayList<List<String>>(); for ( QueryResultsRow r : results ) { l.add( Arrays.asList( new String[] { (String) r.get( "x" ), (String) r.get( "y" ) } ) ); }
The algorithm uses stacks to handle recursion, so the method stack will not blow up.
// Creates an inspector SessionInspector inspector = new SessionInspector( ksession ); // Collects the session info StatefulKnowledgeSessionInfo info = inspector.getSessionInfo(); // Generate a report using the "simple" report template String report = SessionReporter.generateReport( "simple", info, null );
101
from(
"direct:test-with-ep"
4.5.5. Guvnor
4.5.5.1. Guvnor Look & Feel Moving Closer To Native GWT Look
We have removed GWT-Ext from Guvnor and now only use GWT.
102
Guvnor
103
104
Guvnor
105
106
Guvnor
107
rule "no cheddar liked by Fred" when not ( $c : Cheese( name == "Cheddar" ) Person( name == "Fred", favouriteCheese == $c ) ) then .. end
108
Guvnor
109
// from row number: 1 rule "Row 1 dtable" salience 1 dialect "mvel" when $p : Person( name == "Bill" , age != "30" ) then $p.setAge( 12345 ); end // from row number: 2 rule "Row 2 dtable" salience 2 dialect "mvel" when $p : Person( name == "Ben" , age in ( "30", "40", "50" ) ) then $p.setAge( 12345 ); end // from row number: 3 rule "Row 3 dtable" salience 3 dialect "mvel" when $p : Person( name == "Weed" , age != "40" ) then $p.setAge( 12345 ); end // from row number: 4 rule "Row 4 dtable" salience 4 dialect "mvel" when $p : Person( name not in ( "Bill", "Ben", "Weed" ) , age != "50" ) then $p.setAge( 12345 ); end
110
Guvnor
111
Figure 4.61. Editing Spring Context 4.5.5.5.10. Configuring Multiple Guvnor Instances In a Jackrabbit Cluster
We added a new task in drools-ant which helps with configuring multiple Guvnor instances to be able to share their Jackrabbit content.
112
Eclipse
4.5.6. Eclipse
4.5.6.1. Removal of BRL Guided Editor
The BRL Guided Editor has been removed due to lack of interest and it falling behind. Its removal allows more focus on the GWT based Guided Editor in Guvnor. The DRL, text-based, Guided Editor remains unaffected.
drools-examplesorg.drools fusion / droolsexamples-drl using parts) (jBPM org.drools org.drools org.drools org.drools org.drools org.drools org.drools org.drools org.drools org.jbpm
droolsjbpm-expertdocs droolsjbpm-fusiondocs guvnor-repository droolsjbpm-idecommon guvnor-webapp guvnor-bulk-importer guvnor-docs drools-camel-server droolsjbpmintegration-docs jbpm-flow
org.jboss.drools.guvnor.tools guvnor-importer org.drools org.drools org.drools org.drools drools-docs-guvnor drools-server drools-docsintegration drools-flow-core
113
Old groupId org.drools org.drools org.drools org.drools org.drools org.drools org.drools org.drools org.drools org.drools org.drools org.drools
Old artifactId drools-flowcompiler drools-bpmn2 drools-flowpersistence-jpa drools-bam drools-process-task drools-gwt-console drools-gwt-form drools-gwt-graph drools-gwt-war
New groupId org.jbpm org.jbpm org.jbpm org.jbpm org.jbpm org.jbpm org.jbpm org.jbpm org.jbpm
New artifactId jbpm-flow-builder jbpm-bpmn2 jbpm-persistencejpa jbpm-bam jbpm-human-task jbpm-gwt-console jbpm-gwt-form jbpm-gwt-graph jbpm-gwt-war jbpm-gwt-server-war jbpm-workitems jbpm-docs
For example: before, in your pom.xml files, you declared drools-api like this:
And now, afterwards, in your pom.xml files, you declare knowledge-api like this instead:
114
Core
change-set-5.0.xsd
main/resources/change-set-1.0.0.xsd' > <add> <resource source='classpath:org/domain/someRules.drl' type='DRL' /> <resource source='classpath:org/domain/aFlow.drf' type='DRF' /> </add> </change-set>
4.6.2. Core
4.6.2.1. JMX Monitoring
JMX monitoring was added to support KnowledgeBase monitoring. This is specially importand for long running processes like the ones usually required for event processing. Initial integration with JOPR was also added. JMX can be inabled with using the properties setting the knowledge base: drools.mbeans = <enabled|disabled> or this option at runtime kbaseConf.setOption( MBeansOption.ENABLED )
4.6.2.2. Spring
Drools now has extensive Spring support, the XSD can be found in the the drools-spring jar. The namespace is "http://drools.org/schema/drools-spring"
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:drools="http://drools.org/schema/drools-spring" xmlns:camel="http://camel.apache.org/schema/spring" xsi:schemaLocation="http://www.springframework.org/schema/beans http:// www.springframework.org/schema/beans/spring-beans-2.0.xsd http://drools.org/schema/ drools-spring http://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/droolscontainer/drools-spring/src/main/resources/org/drools/container/spring/droolsspring-1.0.0.xsd http://camel.apache.org/schema/spring http:// camel.apache.org/schema/spring/camel-spring.xsd">
115
<drools:resource
id="resource1"
type="DRL"
source="classpath:org/drools/
container/spring/testSpring.drl"/> <drools:kbase id="kbase1"> <drools:resources> <drools:resource type="DRL" source="classpath:org/drools/container/spring/ testSpring.drl"/> <drools:resource ref="resource1"/> <drools:resource source="classpath:org/drools/container/spring/ IntegrationExampleTest.xls" type="DTABLE"> <drools:decisiontable-conf input-type="XLS" worksheet-name="Tables_2" /> </drools:resource> </drools:resources> <drools:configuration> <drools:mbeans enabled="true" /> <drools:event-processing-mode mode="STREAM" /> </drools:configuration> </drools:kbase> </beans>
KnowledgeBase takes the following configurations: "advanced-process-rule-integration, multithread, mbeans, event-processing-mode, accumulate-functions, evaluators and assertbehavior". From the the kbase reference ksessions can be created
<drools:ksession id="ksession1" type="stateless" name="stateless1" kbase="kbase1" / > <drools:ksession id="ksession2" type="stateful" kbase="kbase1" />
Like KnowledgeBases Knowlege sessions can take a number of configurations, including "workitem-handlers, "keep-references", "clock-type", "jpa-persistence".
<drools:ksession id="ksession1" type="stateful" kbase="kbase1" > <drools:configuration> <drools:work-item-handlers> <drools:work-item-handler name="handlername" ref="handlerid" /> </drools:work-item-handlers> <drools:keep-reference enabled="true" /> <drools:clock-type type="REALTIME" />
116
Core
</drools:configuration> </drools:ksession>
<bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.h2.Driver" /> <property name="url" value="jdbc:h2:tcp://localhost/DroolsFlow" /> <property name="username" value="sa" /> <property name="password" value="" /> </bean> <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="ds" /> <property name="persistenceUnitName" value="org.drools.persistence.jpa.local" / > </bean> <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="myEmf" /> </bean> <drools:ksession id="jpaSingleSessionCommandService" type="stateful" kbase="kbase1"> <drools:configuration> <drools:jpa-persistence> <drools:transaction-manager ref="txManager" /> <drools:entity-manager-factory ref="myEmf" /> <drools:variable-persisters> <drools:persister forimplementation="org.drools.persistence.processinstance.persisters.JPAVariablePersister"/ class="javax.persistence.Entity" > <drools:persister forimplementation="org.drools.container.spring.beans.persistence.StringVariablePersister"/ class="java.lang.String" >
Knowledge Sessions can support startup batch scripts, previous versions used the "script" element name, this will be updated to "batch". The following commands are supported: "insert-
117
object", "set-global", "fire-all-rules", "fire-until-halt", "start-process", "signal-event". Anonymous beans or named "ref" attributes may be used.
<drools:ksession id="jpaSingleSessionCommandService" type="stateful" kbase="kbase1"> <drools:script> <drools:insert-object ref="person1" /> <drools:start-process process-id="proc name"> <drools:parameter identifier="varName" ref="varRef" /> </drools:start-process> <drools:fire-all-rules /> </drools:script> </drools:ksession>
ExecutionNodes are supported in Spring , these provide a Context of registered ksessions; this can be used with Camel to provide ksession routing.
<execution-node id="node1" /> <drools:ksession id="ksession1" type="stateless" name="stateless1" kbase="kbase1" node="node1"/ > <drools:ksession id="ksession2" type="stateful" kbase="kbase1" node="node1"/>
4.6.2.3. Camel
Spring can be combined with Camel to provide declarative rule services. a Camel Policy is added from Drools which provides magic for injecting the ClassLoader used by the ksession for any data formatters, it also augments the Jaxb and XStream data formatters. In the case lf Jaxb it adds additional Drools related path info and with XStream it registers Drools related converters and aliases. You can create as many endpoints as you require, using different addresses. The CommandMessagBodyReader is needed to allow the payload to be handled by Camel.
118
Core
Camel routes can then be attached to CXF endpoints, allowing you control over the payload for things like data formatting and executing against Drools ksessions. The DroolsPolicy adds some smarts to the route. If JAXB or XStream are used, it would inject custom paths and converters, it can also set the classloader too on the server side, based on the target ksession. On the client side it automatically unwrapes the Response object. This example unmarshalls the payload using an augmented XStream DataFormat and executes it against the ksession1 instance. The "node" there refers to the ExecutionContext, which is a context of registered ksessions.
<bean id="droolsPolicy" class="org.drools.camel.component.DroolsPolicy" /> <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="cxfrs://bean://rsServer"/> <policy ref="droolsPolicy"> <unmarshal ref="xstream" /> <to uri="drools://node/ksession1" /> <marshal ref="xstream" /> </policy> </route> </camelContext>
The Drools endpoint "drools:node/ksession1" consists of the execution node name followed by a separator and optional knowledge session name. If the knowledge session is not specified the route will look at the "lookup" attribute on the incoming payload instace or in the head attribute "DroolsLookup" to find it.
119
StatefulKnowledgeSession ksession = ... // ... insert facts, fire rules, etc SessionInspector inspector = new SessionInspector( ksession ); StatefulKnowledgeSessionInfo info = inspector.getSessionInfo();
The StatefulKnowledgeSessionInfo instance will contain a lot of relevant data gathered during the analysis of the session. A simple example report template is provided and can be generated with the following API call:
120
Expert
4.6.3. Expert
4.6.3.1. Differential Update
Rete traditional does an update as a retract + assert, for a given fact this causes all partial matches to be destroyed, however during the assert some of which will be recreated again; because they were true before the update and still true after the update. This causes a lot of uneccessary object destruction and creation which puts more load on the Garbage Collector. Now an update is a single pass and inspects the partial matches in place avoiding the unecessary destruction of partial matches. It also removes the need to under go a normalisation process for events and truth maintenance; the normalisation process was where we would look at the activations retracted and activations inserted to figure out what was truly added and what was truly inserted to determine the "diff".
4.6.3.2. Channels
Exit Points have been replaced by the more aptly named channels, we felt this was more appropriate as they may be used by more than juse the rule engine and not an exact oppposte if Entry Points. Where entry points are explicitey related to entering a partition in the Rete network.
final List updated = new ArrayList(); final List removed = new ArrayList(); final List added = new ArrayList(); ViewChangedEventListener listener = new ViewChangedEventListener() { public void rowUpdated(Row row) { updated.add( row.get( "$price" ) ); } public void rowRemoved(Row row) { removed.add( row.get( "$price" ) ); } public void rowAdded(Row row) {
121
added.add( row.get( "$price" ) ); } }; // Open the LiveQuery LiveQuery query = ksession.openLiveQuery( "cheeses", new Object[] { "cheddar", "stilton" }, listener ); ... ... query.dispose() // make sure you call dispose when you want the query to close
A Drools blog article contains an example of Glazed Lists integration for live queries, http://blog.athico.com/2010/07/glazed-lists-examples-for-drools-live.html
timer ( int: <initial delay> <repeat interval>? ) timer ( int: 30s ) timer ( int: 30s 5m ) timer ( cron: <cron expression> ) timer ( cron:* 0/15 * * * ? )
Interval "int:" timers follow the JDK semantics for initial delay optionally followed by a repeat interval. Cron "cron:" timers follow standard cron expressions:
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
Calendars can now controll when rules can fire. The Calendar api is modelled on Quartz http:// www.quartz-scheduler.org/ [http://www.quartz-scheduler.org/] :
122
Expert
They can be used in conjunction with normal rules and rules including timers. The rule calendar attribute can have one or more comma calendar names.
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
123
forall(<separator>?){<codesnippt>}
forall(,) {propertyName == $} forall(&&) {propertyName == $} forall(||) {propertyName == $} forall(||) {propertyNameA == $} && forall(||){propertyNameB == $} etc
4.6.4. Flow
4.6.4.1. BPMN2
As we already announced earlier, the Drools team has decided to support the use of the upcoming BPMN 2.0 specification for specifying business processes using XML. This milestone includes a significant extension of the BPMN2 parser to support more of the BPMN2 features using Drools Flow. More specifically: more extensive event support: much more combinations of event types (start, intermediate and end) and event triggers (including for example error, escalation, timer, conditional and signal events), have been included, as well as (interrupting and non-interrupting) boundary events sub-process parameters diverging inclusive gateway etc. BPMN2 processes have also been integrated in the entire Drools tool chain, to support the entire life cycle of the business process. This includes The ability to use BPMN2 processes in combination with our Eclipse tooling Guvnor as process repository web-based management using the BPM console auditing and debugging domain-specific processes etc.
124
Guvnor
As a result, Drools Flow is not only the first open-source process engine that supports such a significant set of BPMN2 constructs natively, our knowledge-oriented approach also allows you to easily combine your BPMN2 processes with business rules and complex event processing, all using the same APIs and tools.
4.6.5. Guvnor
Appearance has been cleaned, for example less pop ups. Reminders for save after changes in assets and information about actions that were taken, also better error reporting if something goes wrong.
125
4.6.5.1. Discussions
The comments are below the "documentation" section (and of course optional) (and there is an Atom feed to them).
4.6.5.2. Inbox
The inbox feature provides the ability to track what you have opened, or edited - this shows up under an "Inbox" item in the main navigator. http://blog.athico.com/2009/09/inbox-feature-to-trackrecent-changes.html
126
Guvnor
Clicking on the recently opened item will open a listing of all items you have "recently" opened (it tracks a few hundred items that you were last to look at). Recently Edited Any items that you save changes to, or comment on will show up here, once again. Incoming changes This tracks changes made by *other people* to items that are in *your* "Recently Edited" list. When you open these items they then are removed from this list (but remain in your Recently Edited list).
4.6.5.4. DroolsDoc
PDF document containing information about the package and each DRL asset. DroolsDoc for knowledge package can be downloaded from package view under "Information and important URLs"
127
128
Guvnor
129
When using 'from accumulate' The left pattern could be any Fact Type Pattern. The right section of this conditional element is splited in two:
Source Pattern: (Bed $n, in the screenshot) could be any Fact Type, From, Collect or Accumulate pattern. Accumulate function: Here you will find a tabbed panel where you can enter an accumulate function (sum() in the screenshot) or you can create an online custom function using the Custom Code tab.
130
Guvnor
131
132
Guvnor
133
Figure 4.74. Without the Working Set all types are visible
134
Guvnor
135
136
Guvnor
Figure 4.80. Select the working set to validate the age field
137
138
Eclipse
4.6.6. Eclipse
4.6.6.1. Group Rules in outline view
You can now use sorting and grouping for Agenda Groups.
139
140
Drools API
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:
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();
141
A Typical example to load a process resource. Notice the ResourceType is changed, in accordance with the Resource type:
Example 4.26. 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 4.27. 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.
<change-set xmlns='http://drools.org/drools-5.0/change-set'
142
Drools Guvnor
xmlns:xs='http://www.w3.org/2001/XMLSchema-instance' xs:schemaLocation='http://drools.org/drools-5.0/change-set changeset-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>
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 4.30. 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);
143
144
Drools Guvnor
145
146
Drools Guvnor
147
148
Drools Expert
declare StockTick @role( event ) @timestamp( timestampAttr ) companySymbol : String stockPrice : double timestampAttr : long end
149
4.7.3.9. 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".
150
Drools Expert
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:
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.
// 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 ) )
151
end
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:
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.
152
Drools Expert
assignResult.setReceiver( executeResultHandler ); Transformer outTransformer = PipelineFactory.newXStreamToXmlTransformer( BatchExecutionHelper.n outTransformer.setReceiver( assignResult ); KnowledgeRuntimeCommand batchExecution = PipelineFactory.newBatchExecutor(); batchExecution.setReceiver( outTransformer ); Transformer inTransformer = PipelineFactory.newXStreamFromXmlTransformer( BatchExecutionHelper. 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:
<batch-execution> <insert out-identifier='outStilton'> <org.drools.Cheese> <type>stilton</type> <price>25</price> <oldPrice>0</oldPrice> </org.drools.Cheese> </insert> </batch-execution>
<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>
4.7.3.17. Marshalling
The MarshallerFactory is used to marshal and unmarshal StatefulKnowledgeSessions. At the simplest it can be used as follows:
153
// 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.
ByteArrayOutputStream baos = new ByteArrayOutputStream(); Marshaller marshaller = MarshallerFactory.newMarshaller( kbase, new ObjectMarshallingStrategy[] 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:
154
Drools Expert
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectMarshallingStrategyAcceptor identityAceceptor = MarshallerFactory.newClassFilterAcceptor( ObjectMarshallingStrategy identityStratetgy = MarshallerFactory.newIdentityMarshallingStrategy( Marshaller marshaller = MarshallerFactory.newMarshaller( kbase, new ObjectMarshallingStrategy[] marshaller.marshall( baos, ksession ); baos.close();
// Set the interval on the ResourceChangeScannerService if you are to use it and default of 60s is not desirable. ResourceChangeScannerConfiguration sconf = ResourceFactory.getResourceChangeScannerService().ne 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( agent", // the name of the agent "test
155
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.
156
Drools Flow
157
158
Drools Flow
159
<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 droolsprocesses-4.0.xsd" >
160
Drools Flow
<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>
161
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.).
4.7.4.9. JPA
Improved support for persistence (JPA) and transactions (JTA).
Example 4.50. 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( "emfname" ) ); env.set( EnvironmentName.TRANSACTION_MANAGER, TransactionManagerServices.getTransactionManager( StatefulKnowledgeSession JPAKnowledgeService.newStatefulKnowledgeSession( null, ksession = kbase,// 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();
162
Drools Flow
* [Java code constraint] return person.getAge() > 20; * [MVEL action] System.out.println(person.name);
Example 4.52. 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.
163
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 capable of storing more detailed information for one specific 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.
Example 4.53. Both existing and generated beans support event semantics:
164
Drools Fusion
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
165
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.
Example 4.55. 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 );
166
Eclipse IDE
The above pattern will match if SomeEvent happens between 1 minute (1m) and 1 hour and 30 minutes after $anotherEvent.
rule "Allow access" when WorkHours( $s : start, $e : end ) LogIn( time after $s, time before $e ) then // allow access end
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.
167
168
169
170
WorkingMemory wm = rulebase.newWorkingMemory();
StatefulSession wm = rulebase.newStatefulSession();
The StatefulSession object has the same behavior as the Drools 3.0.x WorkingMemory (it even extends the WorkingMemory interface), so there should be no other problems with this fix.
171
rule "Primitive int manual unbox" when $c : Cheese( $price : price ) then $c.setPrice( $price.intValue() * 2 ) end
rule "Primitive support" when $c : Cheese( $price : price ) then $c.setPrice( $price * 2 ) end
172
The Drools update tool can be found as a maven project in the following source repository http:// anonsvn.labs.jboss.com/labs/jbossrules/trunk/experimental/drools-update/ you just need to check it out, and execute the maven clean install action with the project's pom.xml file. After resolve all the class path dependencies you are able to run the toll with the following command:
-f
<filemask>
[-d
The program parameters are very easy to understand as following. -h,--help, Shows a very simple list the usage help -d your source base directory -f pattern for the files to be updated. The format is the same as used by ANT: * = single file, directory ** = any level of subdirectories EXAMPLE: src/main/resources/**/*.drl = matches all DRL files inside any subdirectory of /src/main/resources -s,--sufix the sufix to be added to all updated files
Now, you need to escape '[' and ']' characters, as they have special meaning in regexps. So, the same mapping in Drools 4.0 would be:
173
174
Chapter 5.
If you combine the versions specified in any single row of this table, they are compatible.
175
176