You are on page 1of 56

9/4/2016

Chapter5.TheRuleLanguage

Prev

Next

Chapter5.TheRuleLanguage
5.1.Overview
5.1.1.Arulefile
5.1.2.Whatmakesarule
5.2.Keywords
5.3.Comments
5.3.1.Singlelinecomment
5.3.2.Multilinecomment
5.4.ErrorMessages
5.4.1.Messageformat
5.4.2.ErrorMessagesDescription
5.4.3.OtherMessages
5.5.Package
5.5.1.import
5.5.2.global
5.6.Function
5.7.TypeDeclaration
5.7.1.DeclaringNewTypes
5.7.2.DeclaringMetadata
5.7.3.DeclaringMetadataforExistingTypes
5.7.4.Parameterizedconstructorsfordeclaredtypes
5.7.5.NonTypesafeClasses
5.7.6.AccessingDeclaredTypesfromtheApplicationCode
5.7.7.TypeDeclaration'extends'
5.8.Rule
5.8.1.RuleAttributes
5.8.2.TimersandCalendars
5.8.3.LeftHandSide(when)syntax
5.8.4.TheRightHandSide(then)
5.8.5.ANoteonAutoboxingandPrimitiveTypes
5.9.Query
5.10.DomainSpecificLanguages
5.10.1.WhentoUseaDSL
5.10.2.DSLBasics
5.10.3.AddingConstraintstoFacts
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

1/56

9/4/2016

Chapter5.TheRuleLanguage

5.10.4.DevelopingaDSL
5.10.5.DSLandDSLRReference
5.11.XMLRuleLanguage
5.11.1.WhentouseXML
5.11.2.TheXMLformat
5.11.3.LegacyDrools2.xXMLruleformat
5.11.4.Automatictransformingbetweenformats(XMLandDRL)

5.1.Overview
Drools has a "native" rule language. This format is very light in terms of punctuation, and supports
natural and domain specific languages via "expanders" that allow the language to morph to your
problem domain. This chapter is mostly concerted with this native rule format. The diagrams used to
presentthesyntaxareknownas"railroad"diagrams,andtheyarebasicallyflowchartsforthelanguage
terms. The technically very keen may also refer to DRL.g which is the Antlr3 grammar for the rule
language. If you use the Rule Workbench, a lot of the rule structure is done for you with content
assistance,forexample,type"ru"andpressctrl+space,anditwillbuildtherulestructureforyou.

5.1.1.Arulefile
Arulefileistypicallyafilewitha.drlextension.InaDRLfileyoucanhavemultiplerules,queriesand
functions, as well as some resource declarations like imports, globals and attributes that are assigned
andusedbyyourrulesandqueries.However,youarealsoabletospreadyourrulesacrossmultiplerule
files(inthatcase,theextension.ruleissuggested,butnotrequired)spreadingrulesacrossfilescan
helpwithmanaginglargenumbersofrules.ADRLfileissimplyatextfile.
Theoverallstructureofarulefileis:

Example5.1.Rulesfile
packagepackagename

imports
globals
functions
queries
rules

The order in which the elements are declared is not important, except for the package name that, if
declared,mustbethefirstelementintherulesfile.Allelementsareoptional,soyouwilluseonlythose
youneed.Wewilldiscusseachoftheminthefollowingsections.

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

2/56

9/4/2016

Chapter5.TheRuleLanguage

5.1.2.Whatmakesarule
Fortheinpatients,justasanearlyview,arulehasthefollowingroughstructure:
rule"name"
attributes
when
LHS
then
RHS
end

It's really that simple. Mostly punctuation is not needed, even the double quotes for "name" are
optional,asarenewlines.Attributesaresimple(alwaysoptional)hintstohowtheruleshouldbehave.
LHSistheconditionalpartsoftherule,whichfollowsacertainsyntaxwhichiscoveredbelow.RHSis
basicallyablockthatallowsdialectspecificsemanticcodetobeexecuted.
It is important to note that white space is not important, except in the case of domain specific
languages,wherelinesareprocessedonebyoneandspacesmaybesignificanttothedomainlanguage.

5.2.Keywords
Drools5introducestheconceptofhardandsoftkeywords.
Hard keywords are reserved, you cannot use any hard keyword when naming your domain objects,
properties,methods,functionsandotherelementsthatareusedintheruletext.
Hereisthelistofhardkeywordsthatmustbeavoidedasidentifierswhenwritingrules:
true
false
null

Softkeywordsarejustrecognizedintheircontext,enablingyoutousethesewordsinanyotherplaceif
youwish,although,itisstillrecommendedtoavoidthem,toavoidconfusions,ifpossible.Hereisalist
ofthesoftkeywords:
lockonactive
dateeffective
dateexpires
noloop
autofocus
activationgroup
agendagroup
ruleflowgroup
entrypoint
duration
package
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

3/56

9/4/2016

Chapter5.TheRuleLanguage

import
dialect
salience
enabled
attributes
rule
extend

when
then
template
query
declare
function
global
eval
not
in
or
and
exists
forall

accumulate
collect
from
action
reverse
result
end

over
init

Of course, you can have these (hard and soft) words as part of a method name in camel case, like
notSomething()oraccumulateSomething()therearenoissueswiththatscenario.
Although the 3 hard keywords above are unlikely to be used in your existing domain models, if you
absolutelyneedtousethemasidentifiersinsteadofkeywords,theDRLlanguageprovidestheabilityto
escapehardkeywordsonruletext.Toescapeaword,simplyencloseitingraveaccents,likethis:

Holiday(`true`=="yes")//pleasenotethatDroolswillresolvethatreferencetothemethodHoliday.isTrue(

5.3.Comments
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

4/56

9/4/2016

Chapter5.TheRuleLanguage

Commentsaresectionsoftextthatareignoredbytheruleengine.Theyarestrippedoutwhentheyare
encountered,exceptinsidesemanticcodeblocks,liketheRHSofarule.

5.3.1.Singlelinecomment

Figure5.1.Singlelinecomment

Tocreatesinglelinecomments,youcanuseeither'#'or'//'.Theparserwillignoreanythingintheline
afterthecommentsymbol.Example:
rule"TestingComments"
when
#thisisasinglelinecomment
//thisisalsoasinglelinecomment
eval(true)#thisisacommentinthesamelineofapattern
then
//thisisacommentinsideasemanticcodeblock
#thisisanothercommentinasemanticcodeblock
end

5.3.2.Multilinecomment

Figure5.2.Multilinecomment

Multiline comments are used to comment blocks of text, both in and outside semantic code blocks.
Example:
rule"TestMultilineComments"
when
/*thisisamultilinecomment
inthelefthandsideofarule*/
eval(true)
then
/*andthisisamultilinecomment
intherighthandsideofarule*/
end

5.4.ErrorMessages
Drools 5 introduces standardized error messages. This standardization aims to help users to find and
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

5/56

9/4/2016

Chapter5.TheRuleLanguage

resolveproblemsinaeasierandfasterway.Inthissectionyouwilllearnhowtoidentifyandinterpret
thoseerrormessages,andyouwillalsoreceivesometipsonhowtosolvetheproblemsassociatedwith
them.

5.4.1.Messageformat
Thestandardizationincludestheerrormessageformatandtobetterexplainthisformat,let'susethe
followingexample:

Figure5.3.ErrorMessageFormat

1stBlock:Thisareaidentifiestheerrorcode.
2ndBlock:Lineandcolumninformation.
3rdBlock:Sometextdescribingtheproblem.
4thBlock:Thisisthefirstcontext.Usuallyindicatestherule,function,templateorquerywherethe
erroroccurred.Thisblockisnotmandatory.
5thBlock:Identifiesthepatternwheretheerroroccurred.Thisblockisnotmandatory.

5.4.2.ErrorMessagesDescription

5.4.2.1.101:Noviablealternative
Indicatesthemostcommonerrors,wheretheparsercametoadecisionpointbutcouldn'tidentifyan
alternative.Herearesomeexamples:

Example5.2.
1:ruleone
2:when
3:existsFoo()
4:exitsBar()
5:then
6:end

Theaboveexamplegeneratesthismessage:
[ERR101]Line4:4noviablealternativeatinput'exits'inruleone
At first glance this seems to be valid syntax, but it is not (exits != exists). Let's take a look at next
example:
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

6/56

9/4/2016

Chapter5.TheRuleLanguage

Example5.3.
1:packageorg.drools;
2:rule
3:when
4:Object()
5:then
6:System.out.println("ARHS");
7:end

Nowtheabovecodegeneratesthismessage:
[ERR101]Line3:2noviablealternativeatinput'WHEN'
ThismessagemeansthattheparserencounteredthetokenWHEN,actuallyahardkeyword,butit'sin
thewrongplacesincethetherulenameismissing.
Theerror"noviablealternative"alsooccurswhenyoumakeasimplelexicalmistake.Hereisasample
ofalexicalproblem:

Example5.4.
1:rulesimple_rule
2:when
3:Student(name=="Andy)
4:then
5:end

Theabovecodemissestoclosethequotesandbecauseofthistheparsergeneratesthiserrormessage:
[ERR101]Line0:1noviablealternativeatinput'<eof>'inrulesimple_ruleinpatternStudent

Note
Usually the Line and Column information are accurate, but in some cases (like unclosed
quotes),theparsergeneratesa0:1position.Inthiscaseyoushouldcheckwhetheryou
didn'tforgettoclosequotes,apostrophesorparentheses.

5.4.2.2.102:Mismatchedinput
Thiserrorindicatesthattheparserwaslookingforaparticularsymbolthatitdidntndatthecurrent
inputposition.Herearesomesamples:

Example5.5.

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

7/56

9/4/2016

Chapter5.TheRuleLanguage

1:rulesimple_rule
2:when
3:foo3:Bar(

Theaboveexamplegeneratesthismessage:
[ERR102]Line0:1mismatchedinput'<eof>'expecting')'inrulesimple_ruleinpatternBar
Tofixthisproblem,itisnecessarytocompletetherulestatement.

Note
Usuallywhenyougeta0:1position,itmeansthatparserreachedtheendofsource.

Thefollowingcodegeneratesmorethanoneerrormessage:

Example5.6.
1:packageorg.drools;
2:
3:rule"AvoidNPEonwrongsyntax"
4:when

5:not(Cheese((type=="stilton",price==10)||(type=="brie",price==15))from$cheeseList)
6:then
7:System.out.println("OK");
8:end

Thesearetheerrorsassociatedwiththissource:
[ERR 102] Line 5:36 mismatched input ',' expecting ')' in rule "Avoid NPE on wrong syntax" in
patternCheese
[ERR101]Line5:57noviablealternativeatinput'type'inrule"AvoidNPEonwrongsyntax"
[ERR102]Line5:106mismatchedinput')'expecting'then'inrule"AvoidNPEonwrongsyntax"
Note that the second problem is related to the first. To fix it, just replace the commas (',') by AND
operator('&&').

Note
In some situations you can get more than one error message. Try to fix one by one,
startingatthefirstone.Someerrormessagesaregeneratedmerelyasconsequencesof
othererrors.

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

8/56

9/4/2016

Chapter5.TheRuleLanguage

5.4.2.3.103:Failedpredicate
Avalidatingsemanticpredicateevaluatedtofalse.Usuallythesesemanticpredicatesareusedtoidentify
softkeywords.Thissampleshowsexactlythissituation:

Example5.7.
1:packagenesting;
2:dialect"mvel"
3:
4:importorg.drools.Person
5:importorg.drools.Address
6:
7:fdsfdsfds
8:
9:rule"testsomething"
10:when
11:p:Person(name=="Michael")
12:then
13:p.name="other";
14:System.out.println(p.name);
15:end

Withthissample,wegetthiserrormessage:
[ERR

103]

Line

7:0

rule

'rule_key'

failed

predicate:

{(validateIdentifierKey(DroolsSoftKeywords.RULE))}?inrule
Thefdsfdsfdstextisinvalidandtheparsercouldntidentifyitasthesoftkeywordrule.

Note
Thiserrorisverysimilarto102:Mismatchedinput,butusuallyinvolvessoftkeywords.

5.4.2.4.104:Trailingsemicolonnotallowed
This error is associated with the eval clause, where its expression may not be terminated with a
semicolon.Checkthisexample:

Example5.8.
1:rulesimple_rule
2:when
3:eval(abc();)
4:then
5:end

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

9/56

9/4/2016

Chapter5.TheRuleLanguage

Duetothetrailingsemicolonwithineval,wegetthiserrormessage:
[ERR104]Line3:4trailingsemicolonnotallowedinrulesimple_rule
Thisproblemissimpletofix:justremovethesemicolon.

5.4.2.5.105:EarlyExit
Therecognizercametoasubruleinthegrammarthatmustmatchanalternativeatleastonce,butthe
subruledidnotmatchanything.Simplyput:theparserhasenteredabranchfromwherethereisno
wayout.Thisexampleillustratesit:

Example5.9.
1:templatetest_error
2:aas11;
3:end

Thisisthemessageassociatedtotheabovesample:
[ERR105]Line2:2required(...)+loopdidnotmatchanythingatinput'aa'intemplatetest_error
Tofixthisproblemitisnecessarytoremovethenumericvalueasitisneitheravaliddatatypewhich
mightbeginanewtemplateslotnorapossiblestartforanyotherrulefileconstruct.

5.4.3.OtherMessages
Anyothermessagemeansthatsomethingbadhashappened,sopleasecontactthedevelopmentteam.

5.5.Package
Apackageisacollectionofrulesandotherrelatedconstructs,suchasimportsandglobals.Thepackage
members are typically related to each other perhaps HR rules, for instance. A package represents a
namespace,which ideally is kept unique for a given grouping of rules. The package name itself is the
namespace,andisnotrelatedtofilesorfoldersinanyway.
Itispossibletoassemblerulesfrommultiplerulesources,andhaveonetoplevelpackageconfiguration
thatalltherulesarekeptunder(whentherulesareassembled).Although,itisnotpossibletomerge
into the same package resources declared under different names. A single Rulebase may, however,
containmultiplepackagesbuiltonit.Acommonstructureistohavealltherulesforapackageinthe
samefileasthepackagedeclaration(sothatisitentirelyselfcontained).
The following railroad diagram shows all the components that may make up a package. Note that a
packagemusthaveanamespaceandbedeclaredusingstandardJavaconventionsforpackagenames
i.e., no spaces, unlike rule names which allow spaces. In terms of the order of elements, they can
appearinanyorderintherulefile,withtheexceptionofthe packagestatement,whichmustbeatthe
topofthefile.Inallcases,thesemicolonsareoptional.
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

10/56

9/4/2016

Chapter5.TheRuleLanguage

Figure5.4.package

Noticethatanyruleatttribute(asdescribedthesectionRuleAttributes)mayalsobewrittenatpackage
level,supersedingtheattribute'sdefaultvalue.Themodifieddefaultmaystillbereplacedbyanattribute
settingwithinarule.

5.5.1.import

Figure5.5.import

ImportstatementsworklikeimportstatementsinJava.Youneedtospecifythefullyqualifiedpathsand
typenamesforanyobjectsyouwanttouseintherules.Droolsautomaticallyimportsclassesfromthe
Javapackageofthesamename,andalsofromthepackagejava.lang.

5.5.2.global

Figure5.6.global

Withglobalyoudefineglobalvariables.Theyareusedtomakeapplicationobjectsavailabletotherules.
Typically,theyareusedtoprovidedataorservicesthattherulesuse,especiallyapplicationservicesused
inruleconsequences,andtoreturndatafromtherules,likelogsorvaluesaddedinruleconsequences,
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

11/56

9/4/2016

Chapter5.TheRuleLanguage

orfortherulestointeractwiththeapplication,doingcallbacks.GlobalsarenotinsertedintotheWorking
Memory,andthereforeaglobalshouldneverbeusedtoestablishconditionsinrulesexceptwhenithas
aconstantimmutablevalue.Theenginecannotbenotifiedaboutvaluechangesofglobalsanddoesnot
tracktheirchanges.Incorrectuseofglobalsinconstraintsmayyieldsurprisingresultssurprisingina
badway.
Ifmultiplepackagesdeclareglobalswiththesameidentifiertheymustbeofthesametypeandallof
themwillreferencethesameglobalvalue.
Inordertouseglobalsyoumust:
1. Declareyourglobalvariableinyourrulesfileanduseitinrules.Example:
globaljava.util.ListmyGlobalList;
rule"Usingaglobal"
when
eval(true)
then
myGlobalList.add("HelloWorld");
end

2. Settheglobalvalueonyourworkingmemory.Itisabestpracticetosetallglobalvaluesbefore
assertinganyfacttotheworkingmemory.Example:
Listlist=newArrayList();
WorkingMemorywm=rulebase.newStatefulSession();
wm.setGlobal("myGlobalList",list);

Note that these are just named instances of objects that you pass in from your application to the
workingmemory.Thismeansyoucanpassinanyobjectyouwant:youcouldpassinaservicelocator,
orperhapsaserviceitself.WiththenewfromelementitisnowcommontopassaHibernatesessionasa
global,toallowfromtopulldatafromanamedHibernatequery.
One example may be an instance of a Email service. In your integration code that is calling the rule
engine,youobtainyouremailServiceobject,andthensetitintheworkingmemory.IntheDRL,you
declare that you have a global of type EmailService, and give it the name "email". Then in your rule
consequences,youcanusethingslikeemail.sendSMS(number,message).
Globalsarenotdesignedtosharedatabetweenrulesandtheyshouldneverbeusedforthatpurpose.
Rulesalwaysreasonandreacttotheworkingmemorystate,soifyouwanttopassdatafromruleto
rule,assertthedataasfactsintotheworkingmemory.
Itisstronglydiscouragedtosetorchangeaglobalvaluefrominsideyourrules.Werecommendtoyou
alwayssetthevaluefromyourapplicationusingtheworkingmemoryinterface.

5.6.Function

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

12/56

9/4/2016

Chapter5.TheRuleLanguage

Figure5.7.function

Functionsareawaytoputsemanticcodeinyourrulesourcefile,asopposedtoinnormalJavaclasses.
Theycan'tdoanythingmorethanwhatyoucandowithhelperclasses.(Infact,thecompilergenerates
thehelperclassforyoubehindthescenes.)Themainadvantageofusingfunctionsinaruleisthatyou
cankeepthelogicallinoneplace,andyoucanchangethefunctionsasneeded(whichcanbeagoodor
abadthing).Functionsaremostusefulforinvokingactionsontheconsequence(then) part of a rule,
especiallyifthatparticularactionisusedoverandoveragain,perhapswithonlydifferingparametersfor
eachrule.
Atypicalfunctiondeclarationlookslike:
functionStringhello(Stringname){
return"Hello"+name+"!";
}

Note that the function keyword is used, even though its not really part of Java. Parameters to the
functionaredefinedasforamethod,andyoudon'thavetohaveparametersiftheyarenotneeded.
Thereturntypeisdefinedjustlikeinaregularmethod.
Alternatively,youcoulduseastaticmethodinahelperclass,e.g.,Foo.hello().Droolssupportstheuse
offunctionimports,soallyouwouldneedtodois:
importfunctionmy.package.Foo.hello

Irrespectiveofthewaythefunctionisdefinedorimported,youuseafunctionbycallingitbyitsname,
intheconsequenceorinsideasemanticcodeblock.Example:
rule"usingastaticfunction"
when
eval(true)
then
System.out.println(hello("Bob"));
end

5.7.TypeDeclaration

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

13/56

9/4/2016

Chapter5.TheRuleLanguage

Figure5.8.meta_data

Figure5.9.type_declaration

Typedeclarationshavetwomaingoalsintherulesengine:toallowthedeclarationofnewtypes,andto
allowthedeclarationofmetadatafortypes.
Declaring new types: Drools works out of the box with plain Java objects as facts. Sometimes,
however,usersmaywanttodefinethemodeldirectlytotherulesengine,withoutworryingabout
creatingmodelsinalowerlevellanguagelikeJava.Atothertimes,thereisadomainmodelalready
built,buteventuallytheuserwantsorneedstocomplementthismodelwithadditionalentitiesthat
areusedmainlyduringthereasoningprocess.
Declaring metadata: facts may have meta information associated to them. Examples of meta
informationincludeanykindofdatathatisnotrepresentedbythefactattributesandisconsistent
among all instances of that fact type. This meta information may be queried at runtime by the
engineandusedinthereasoningprocess.
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

14/56

9/4/2016

Chapter5.TheRuleLanguage

5.7.1.DeclaringNewTypes
Todeclareanewtype,allyouneedtodoisusethekeyword declare,followedbythelistoffields,and
thekeywordend.

Example5.10.Declaringanewfacttype:Address
declareAddress
number:int
streetName:String
city:String
end

Thepreviousexampledeclaresanewfacttypecalled Address.Thisfacttypewillhavethreeattributes:
number, streetName and city. Each attribute has a type that can be any valid Java type, including any

otherclasscreatedbytheuserorevenotherfacttypespreviouslydeclared.
Forinstance,wemaywanttodeclareanotherfacttypePerson:

Example5.11.declaringanewfacttype:Person
declarePerson
name:String
dateOfBirth:java.util.Date
address:Address
end

Aswecanseeonthepreviousexample, dateOfBirthisoftype java.util.Date,fromtheJavaAPI,while


addressisofthepreviouslydefinedfacttypeAddress.

Youmayavoidhavingtowritethefullyqualifiednameofaclasseverytimeyouwriteitbyusingthe
importclause,aspreviouslydiscussed.

Example5.12.Avoidingtheneedtousefullyqualifiedclassnamesbyusingimport
importjava.util.Date
declarePerson
name:String
dateOfBirth:Date
address:Address
end

Whenyoudeclareanewfacttype,Droolswill,atcompiletime,generate bytecode that implements a


https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

15/56

9/4/2016

Chapter5.TheRuleLanguage

Javaclassrepresentingthefacttype.ThegeneratedJavaclasswillbeaonetooneJavaBeanmapping
ofthetypedefinition.So,forthepreviousexample,thegeneratedJavaclasswouldbe:

Example5.13.generatedJavaclassforthepreviousPersonfacttypedeclaration
publicclassPersonimplementsSerializable{
privateStringname;
privatejava.util.DatedateOfBirth;
privateAddressaddress;
//emptyconstructor
publicPerson(){...}
//constructorwithallfields
publicPerson(Stringname,DatedateOfBirth,Addressaddress){...}
//ifkeysaredefined,constructorwithkeys
publicPerson(...keys...){...}
//gettersandsetters
//equals/hashCode
//toString
}

SincethegeneratedclassisasimpleJavaclass,itcanbeusedtransparentlyintherules,likeanyother
fact.

Example5.14.Usingthedeclaredtypesinrules
rule"UsingadeclaredType"
when
$p:Person(name=="Bob")
then
//InsertMark,whoisBob'smate.
Personmark=newPerson();
mark.setName("Mark");
insert(mark);
end

5.7.2.DeclaringMetadata
Metadata may be assigned to several different constructions in Drools: fact types, fact attributes and
rules.Droolsusestheatsign('@')tointroducemetadata,anditalwaysusestheform:
@metadata_key(metadata_value)

Theparenthesizedmetadata_valueisoptional.

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

16/56

9/4/2016

Chapter5.TheRuleLanguage

For instance, if you want to declare a metadata attribute like author, whose value is Bob, you could
simplywrite:

Example5.15.Declaringametadataattribute
@author(Bob)

Droolsallowsthedeclarationofanyarbitrarymetadataattribute,butsomewillhavespecialmeaningto
the engine, while others are simply available for querying at runtime. Drools allows the declaration of
metadatabothforfacttypesandforfactattributes.Anymetadatathatisdeclaredbeforetheattributes
ofafacttypeareassignedtothefacttype,whilemetadatadeclaredafteranattributeareassignedto
thatparticularattribute.

Example5.16.Declaringmetadataattributesforfacttypesandattributes
importjava.util.Date
declarePerson
@author(Bob)
@dateOfCreation(01Feb2009)
name:String@key@maxLength(30)
dateOfBirth:Date
address:Address
end

In the previous example, there are two metadata items declared for the fact type (@author and
@dateOfCreation)andtwomoredefinedforthenameattribute(@keyand@maxLength).Pleasenotethatthe
@keymetadatahasnorequiredvalue,andsotheparenthesesandthevaluewereomitted.:

@positioncanbeusedtodeclarethepositionofafield,overridingthedefaultdeclaredorder.Thisisused
forpositionalconstraintsinpatterns.
declareCheese
name:String@position(1)
shop:String@position(2)
price:int@position(0)
end

5.7.3.DeclaringMetadataforExistingTypes
Drools allows the declaration of metadata attributes for existing types in the same way as when
declaringmetadataattributesfornewfacttypes.Theonlydifferenceisthattherearenofieldsinthat
declaration.
Forinstance,ifthereisaclassorg.drools.examples.Person,andonewantstodeclaremetadataforit,it's
possibletowritethefollowingcode:
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

17/56

9/4/2016

Chapter5.TheRuleLanguage

Example5.17.Declaringmetadataforanexistingtype
importorg.drools.examples.Person
declarePerson
@author(Bob)
@dateOfCreation(01Feb2009)
end

Insteadofusingtheimport,itisalsopossibletoreferencetheclassbyitsfullyqualifiedname,butsince
theclasswillalsobereferencedintherules,itisusuallyshortertoaddtheimportandusethe short
classnameeverywhere.

Example5.18.Declaringmetadatausingthefullyqualifiedclassname
declareorg.drools.examples.Person
@author(Bob)
@dateOfCreation(01Feb2009)
end

5.7.4.Parameterizedconstructorsfordeclaredtypes
Generateconstructorswithparametersfordeclaredtypes.
Example:foradeclaredtypelikethefollowing:
declarePerson
firstName:String@key
lastName:String@key
age:int
end

Thecompilerwillimplicitlygenerate3constructors:onewithoutparameters,onewiththe@keyfields,
andonewithallfields.
Person()//parameterlessconstructor
Person(StringfirstName,StringlastName)
Person(StringfirstName,StringlastName,intage)

5.7.5.NonTypesafeClasses
@typesafe( <boolean>) has been added to type declarations. By default all type declarations are
compiled with type safety enabled @typesafe( false ) provides a means to override this behaviour by
permittingafallback,totypeunsafeevaluationwhereallconstraintsaregeneratedasMVELconstraints
and executed dynamically. This can be important when dealing with collections that do not have any
genericsormixedtypecollections.
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

18/56

9/4/2016

Chapter5.TheRuleLanguage

5.7.6.AccessingDeclaredTypesfromtheApplicationCode
Declaredtypesareusuallyusedinsiderulesfiles,whileJavamodelsareusedwhensharingthemodel
between rules and applications. Although, sometimes, the application may need to access and handle
factsfromthedeclaredtypes,especiallywhentheapplicationiswrappingtherulesengineandproviding
higherlevel,domainspecificuserinterfacesforrulesmanagement.
Insuchcases,thegeneratedclassescanbehandledasusualwiththeJavaReflectionAPI,but,aswe
know,thatusuallyrequiresalotofworkforsmallresults.Therefore,DroolsprovidesasimplifiedAPIfor
themostcommonfacthandlingtheapplicationmaywanttodo.
The first important thing to realize is that a declared fact will belong to the package where it was
declared.So,forinstance,intheexamplebelow, Personwillbelongtothe org.drools.examplespackage,
andsothefullyqualifiednameofthegeneratedclasswillbeorg.drools.examples.Person.

Example5.19.Declaringatypeintheorg.drools.examplespackage
packageorg.drools.examples
importjava.util.Date
declarePerson
name:String
dateOfBirth:Date
address:Address
end

Declared types, as discussed previously, are generated at knowledge base compilation time, i.e., the
application will only have access to them at application run time. Therefore, these classes are not
availablefordirectreferencefromtheapplication.
Droolsthenprovidesaninterfacethroughwhichuserscanhandledeclared types from the application
code: org.drools.definition.type.FactType. Through this interface, the user can instantiate, read and
writefieldsinthedeclaredfacttypes.

Example5.20.HandlingdeclaredfacttypesthroughtheAPI
//getareferencetoaknowledgebasewithadeclaredtype:
KnowledgeBasekbase=...
//getthedeclaredFactType
FactTypepersonType=kbase.getFactType("org.drools.examples",
"Person");
//handlethetypeasnecessary:
//createinstances:
Objectbob=personType.newInstance();
//setattributesvalues
personType.set(bob,
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

19/56

9/4/2016

Chapter5.TheRuleLanguage

"name",
"Bob");
personType.set(bob,
"age",
42);
//insertfactintoasession
StatefulKnowledgeSessionksession=...
ksession.insert(bob);
ksession.fireAllRules();
//readattributes
Stringname=personType.get(bob,"name");
intage=personType.get(bob,"age");

TheAPIalsoincludesotherhelpfulmethods,likesettingalltheattributesatonce,readingvaluesfroma
Map,orreadingallattributesatonce,intoaMap.
Although the API is similar to Java reflection (yet much simpler to use), it does not use reflection
underneath,relyingonmuchmoreperformantaccessorsimplementedwithgeneratedbytecode.

5.7.7.TypeDeclaration'extends'
Typedeclarationsnowsupport'extends'keywordforinheritance
InordertoextendatypedeclaredinJavabyaDRLdeclaredsubtype,repeatthesupertypeinadeclare
statementwithoutanyfields.
importorg.people.Person
declarePerson
end
declareStudentextendsPerson
school:String
end
declareLongTermStudentextendsStudent
years:int
course:String
end

5.8.Rule

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

20/56

9/4/2016

Chapter5.TheRuleLanguage

Figure5.10.rule

Arulespecifiesthatwhenaparticularsetofconditionsoccur,specifiedintheLeftHandSide(LHS),then
do what queryis specified as a list of actions in the Right Hand Side (RHS). A common question from
usersis"Whyusewheninsteadofif?""When"waschosenover"if"because"if"isnormallypartofa
proceduralexecutionflow,where,ataspecificpointintime,aconditionistobechecked.Incontrast,
"when"indicatesthattheconditionevaluationisnottiedtoaspecificevaluationsequenceorpointin
time, but that it happens continually, at any time during the life time of the engine whenever the
conditionismet,theactionsareexecuted.
Arulemusthaveaname,uniquewithinitsrulepackage.IfyoudefinearuletwiceinthesameDRLit
producesanerrorwhileloading.IfyouaddaDRLthatincludesarulenamealreadyinthepackage,it
replacesthepreviousrule.Ifarulenameistohavespaces,thenitwillneedtobeenclosed in double
quotes(itisbesttoalwaysusedoublequotes).
Attributesdescribedbelowareoptional.Theyarebestwrittenoneperline.
TheLHSoftherulefollowsthe whenkeyword(ideallyonanewline),similarlytheRHSfollowsthe then
keyword (again, ideally on a newline). The rule is terminated by the keyword end. Rules cannot be
nested.

Example5.21.RuleSyntaxOverview
rule"<name>"
<attribute>*
when
<conditionalelement>*
then
<action>*
end

Example5.22.Asimplerule
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

21/56

9/4/2016

Chapter5.TheRuleLanguage

rule"Approveifnotrejected"
salience100
agendagroup"approval"
when
notRejection()
p:Policy(approved==false,policyState:status)
existsDriver(age>25)
Process(status==policyState)
then
log("APPROVED:duetonoobjections.");
p.setApproved(true);
end

5.8.1.RuleAttributes
Ruleattributesprovideadeclarativewaytoinfluencethebehavioroftherule.Somearequitesimple,
whileothersarepartofcomplexsubsystemssuchasruleflow.TogetthemostfromDroolsyoushould
makesureyouhaveaproperunderstandingofeachattribute.

Figure5.11.ruleattributes

noloop

defaultvalue:false
type:Boolean

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

22/56

9/4/2016

Chapter5.TheRuleLanguage

When a rule's consequence modifies a fact it may cause the rule to activate again, causing an
infiniteloop.SettingnolooptotruewillskipthecreationofanotherActivationfortherulewiththe
currentsetoffacts.
ruleflowgroup

defaultvalue:N/A
type:String
Ruleflow is a Drools feature that lets you exercise control over the firing of rules. Rules that are
assembledbythesameruleflowgroupidentifierfireonlywhentheirgroupisactive.
lockonactive

defaultvalue:false
type:Boolean
Wheneveraruleflowgroupbecomesactiveoranagendagroupreceivesthefocus,anyrulewithin
that group that has lockonactive set to true will not be activated any more irrespective of the
originoftheupdate,theactivationofamatchingruleisdiscarded.Thisisastrongerversionofno
loop,becausethechangecouldnowbecausednotonlybytheruleitself.It's ideal for calculation
ruleswhereyouhaveanumberofrulesthatmodifyafactandyoudon'twantanyrulerematching
andfiring again. Only when the ruleflowgroup is no longer active or the agendagroup loses the
focus those rules with lockonactive set to true become eligible again for their activations to be
placedontotheagenda.
salience

defaultvalue:0
type:integer
Eachrulehasanintegersalienceattributewhichdefaultstozeroandcanbenegativeorpositive.
Salienceisaformofprioritywhereruleswithhighersaliencevaluesaregivenhigherprioritywhen
orderedintheActivationqueue.
Droolsalsosupportsdynamicsaliencewhereyoucanuseanexpressioninvolvingboundvariables.
Example5.23.DynamicSalience
rule"Fireinrankorder1,2,.."
salience($rank)
when
Element($rank:rank,...)
then
...
end

agendagroup

defaultvalue:MAIN
type:String
AgendagroupsallowtheusertopartitiontheAgendaprovidingmoreexecutioncontrol.Onlyrulesin
theagendagroupthathasacquiredthefocusareallowedtofire.

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

23/56

9/4/2016

Chapter5.TheRuleLanguage

autofocus

defaultvalue:false
type:Boolean
When a rule is activated where the autofocusvalue is true and the rule's agenda group does not
havefocusyet,thenitisgivenfocus,allowingtheruletopotentiallyfire.
activationgroup

defaultvalue:N/A
type:String
Rulesthatbelongtothesameactivationgroup,identifiedbythisattribute'sstringvalue,willonly
fireexclusively.Inotherwords,thefirstruleinanactivationgrouptofirewillcanceltheotherrules'
activations,i.e.,stopthemfromfiring.
Note:ThisusedtobecalledXorgroup,buttechnicallyit'snotquiteanXor.Youmaystillhearpeople
mentionXorgroupjustswapthatterminyourmindwithactivationgroup.
dialect

defaultvalue:asspecifiedbythepackage
type:String
possiblevalues:"java"or"mvel"
Thedialectspeciesthelanguagetobeusedforanycodeexpressions in the LHS or the RHS code
block.Currentlytwodialectsareavailable,JavaandMVEL.Whilethedialectcanbespecifiedatthe
packagelevel,thisattributeallowsthepackagedefinitiontobeoverriddenforarule.
dateeffective

defaultvalue:N/A
type:String,containingadateandtimedefinition
Arulecanonlyactivateifthecurrentdateandtimeisafterdateeffectiveattribute.
dateexpires

defaultvalue:N/A
type:String,containingadateandtimedefinition
Arulecannotactivateifthecurrentdateandtimeisafterthedateexpiresattribute.
duration

defaultvalue:nodefaultvalue
type:long
Thedurationdictatesthattherulewillfireafteraspecifiedduration,ifitisstilltrue.

Example5.24.Someattributeexamples
rule"myrule"
salience42
agendagroup"number1"
when...
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

24/56

9/4/2016

Chapter5.TheRuleLanguage

5.8.2.TimersandCalendars
Rules now suport both interval and cron based timers, which replace the now deprecated duration
attribute.

Example5.25.Sampletimerattributeuses
timer(int:<initialdelay><repeatinterval>?)
timer(int:30s)
timer(int:30s5m)
timer(cron:<cronexpression>)
timer(cron:*0/15***?)

Interval(indicatedby"int:")timersfollowthesemanticsofjava.util.Timerobjects,withaninitialdelay
and an optional repeat interval. Cron (indicated by "cron:") timers follow standard Unix cron
expressions:

Example5.26.ACronExample
rule"SendSMSevery15minutes"
timer(cron:*0/15***?)
when
$a:Alarm(on==true)
then
channels["sms"].insert(newSms($a.mobileNumber,"Thealarmisstillon");
end

Calendarsareusedtocontrolwhenrulescanfire.TheCalendarAPIismodelledonQuartz:

Example5.27.AdaptingaQuartzCalendar
CalendarweekDayCal=QuartzHelper.quartzCalendarAdapter(org.quartz.CalendarquartzCal)

CalendarsareregisteredwiththeStatefulKnowledgeSession:

Example5.28.RegisteringaCalendar
ksession.getCalendars().set("weekday",weekDayCal);

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

25/56

9/4/2016

Chapter5.TheRuleLanguage

They can be used in conjunction with normal rules and rules including timers. The rule attribute
"calendars"maycontainoneormorecommaseparatedcalendarnameswrittenasstringliterals.

Example5.29.UsingCalendarsandTimerstogether
rule"weekdaysarehighpriority"
calendars"weekday"
timer(int:01h)
when
Alarm()
then
send("priorityhighwehaveanalarm
);
end
rule"weekendarelowpriority"
calendars"weekend"
timer(int:04h)
when
Alarm()
then
send("prioritylowwehaveanalarm
);
end

5.8.3.LeftHandSide(when)syntax

5.8.3.1.WhatistheLeftHandSide?
TheLeftHandSide(LHS)isacommonnamefortheconditionalpartoftherule.Itconsistsofzeroor
more Conditional Elements. If the LHS is empty, it will be considered as a condition element that is
alwaystrueanditwillbeactivatedonce,whenanewWorkingMemorysessioniscreated.

Figure5.12.LeftHandSide

Example5.30.RulewithoutaConditionalElement
rule"noCEs"
when
//empty
then
...//actions(executedonce)
end
#Theaboveruleisinternallyrewrittenas:
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

26/56

9/4/2016

Chapter5.TheRuleLanguage

rule"eval(true)"
when
eval(true)
then
...//actions(executedonce)
end

Conditional elements work on one or more patterns (which are described below). The most common
conditionalelementis" and".ThereforeitisimplicitwhenyouhavemultiplepatternsintheLHSofarule
thatarenotconnectedinanyway:

Example5.31.Implicitand
rule"2unconnectedpatterns"
when
Pattern1()
Pattern2()
then
...//actions
end
#Theaboveruleisinternallyrewrittenas:
rule"2andconnectedpatterns"
when
Pattern1()
andPattern2()
then
...//actions
end

Note
An" and"cannothavealeadingdeclarationbinding(unlikeforexampleor).Thisisobvious,
since a declaration can only reference a single fact at a time, and when the " and" is
satisfieditmatchesbothfactssowhichfactwouldthedeclarationbindto?
//Compileerror
$person:(Person(name=="Romeo")andPerson(name=="Juliet"))

5.8.3.2.Pattern(conditionalelement)

5.8.3.2.1.Whatisapattern?
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

27/56

9/4/2016

Chapter5.TheRuleLanguage

ApatternelementisthemostimportantConditionalElement.Itcanpotentiallymatchoneachfactthat
isinsertedintheworkingmemory.
Apatterncontainsofzeroormoreconstraintsandhasanoptionalpatternbinding.Therailroaddiagram
belowshowsthesyntaxforthis.

Figure5.13.Pattern

In its simplest form, with no constraints, a pattern matches against a fact of the given type. In the
followingcasethetypeis Cheese,whichmeansthatthepatternwillmatchagainstall Personobjectsin
theWorkingMemory:
Person()

Thetypeneednotbetheactualclassofsomefactobject.Patternsmayrefertosuperclassesoreven
interfaces,therebypotentiallymatchingfactsfrommanydifferentclasses.
Object()//matchesallobjectsintheworkingmemory

Inside of the pattern parenthesis is where all the action happens: it defines the constraints for that
pattern.Forexample,withaagerelatedconstraint:
Person(age==100)

Note
Forbackwardscompatibilityreasonsit'sallowedtosuffixpatternswiththe;character.But
itisnotrecommendedtodothat.

5.8.3.2.2.Patternbinding
Forreferringtothematchedobject,useapatternbindingvariablesuchas$p.

Example5.32.Patternwithabindingvariable
rule...
when
$p:Person()
then
System.out.println("Person"+$p);
end

Theprefixeddollarsymbol($)isjustaconventionitcanbeusefulincomplexruleswhereithelpsto
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

28/56

9/4/2016

Chapter5.TheRuleLanguage

easilydifferentiatebetweenvariablesandfields,butitisnotmandatory.

5.8.3.3.Constraint(partofapattern)

5.8.3.3.1.Whatisaconstraint?
Aconstraintisanexpressionthatreturns trueor false.Thisexamplehasaconstraintthatstates5is
smallerthan6:
Person(5<6)//justanexample,asconstraintslikethiswouldbeuselessinarealpattern

In essence, it's a Java expression with some enhancements (such as property access) and a few
differences(suchasequals()semanticsfor==).Let'stakeadeeperlook.

5.8.3.3.2.PropertyaccessonJavaBeans(POJO's)
Anybeanpropertycanbeuseddirectly.AbeanpropertyisexposedusingastandardJavabeangetter:a
methodgetMyProperty()(orisMyProperty()foraprimitiveboolean)whichtakesnoargumentsandreturn
something.Forexample:theagepropertyiswrittenasageinDRLinsteadofthegettergetAge():
Person(age==50)
//thisisthesameas:
Person(getAge()==50)

DroolsusesthestandardJDKIntrospectorclasstodothismapping,soitfollowsthestandardJavabean
specification.

Note
Werecommendusingpropertyaccess(age)overusinggettersexplicitly(getAge())because
ofperformanceenhancementsthroughfieldindexing.

Warning
Propertyaccessorsmustnotchangethestateoftheobjectinawaythatmayeffectthe
rules. Remember that the rule engine effectively caches the results of its matching in
betweeninvocationstomakeitfaster.
publicintgetAge(){
age++;//DoNOTdothis
returnage;
}

publicintgetAge(){
Datenow=DateUtil.now();//DoNOTdothis
returnDateUtil.differenceInYears(now,birthday);
}
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

29/56

9/4/2016

Chapter5.TheRuleLanguage

To solve this latter case, insert a fact that wraps the current date into working memory
andupdatethatfactbetweenfireAllRulesasneeded.

Note
Thefollowingfallbackapplies:ifthegetterofapropertycannotbefound,thecompilerwill
resorttousingthepropertynameasamethodnameandwithoutarguments:
Person(age==50)
//IfPerson.getAge()doesnotexists,thisfallsbackto:
Person(age()==50)

Nestedpropertyaccessisalsosupported:
Person(address.houseNumber==50)
//thisisthesameas:
Person(getAddress().getHouseNumber()==50)

Nestedpropertiesarealsoindexed.

Warning
Inastatefulsession,careshouldbetakenwhenusingnestedaccessors as the Working
Memoryisnotawareofanyofthenestedvalues,anddoesnotknowwhentheychange.
Eitherconsiderthemimmutablewhileanyoftheirparentreferencesareinsertedintothe
WorkingMemory.Or,instead,ifyouwishtomodifyanestedvalueyoushouldmarkallof
the outer facts as updated. In the above example, when the houseNumber changes, any
PersonwiththatAddressmustbemarkedasupdated.

5.8.3.3.3.Javaexpression
You can use any Java expression that returns a boolean as a constraint inside the parentheses of a
pattern.Javaexpressionscanbemixedwithotherexpressionenhancements,suchaspropertyaccess:
Person(age==50)

It is possible to change the evaluation priority by using parentheses, as in any logic or mathematical
expression:
Person(age>100&&(age%10==0))

ItispossibletoreuseJavamethods:
Person(Math.round(weight/(height*height))<25.0)

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

30/56

9/4/2016

Chapter5.TheRuleLanguage

Warning
Asforpropertyaccessors,methodsmustnotchangethestateoftheobjectinawaythat
may affect the rules. Any method executed on a fact in the LHS should be a read only
method.
Person(incrementAndGetAge()==10)//DoNOTdothis

Warning
The state of a fact should not change between rule invocations (unless those facts are
markedasupdatedtotheworkingmemoryoneverychange):
Person(System.currentTimeMillis()%1000==0)//DoNOTdothis

NormalJavaoperatorprecedenceapplies,seetheoperatorprecedencelistbelow.

Important
AlloperatorshavenormalJavasemanticsexceptfor==and!=.
The==operatorhasnullsafeequals()semantics:
//Similarto:java.util.Objects.equals(person.getFirstName(),"John")
//so(because"John"isnotnull)similarto:
//"John".equals(person.getFirstName())
Person(firstName=="John")

The!=operatorhasnullsafe!equals()semantics:
//Similarto:!java.util.Objects.equals(person.getFirstName(),"John")
Person(firstName!="John")

Type coercion is always attempted if the field and the value are of different types exceptions will be
thrown if a bad coercion is attempted. For instance, if "ten" is provided as a string in a numeric
evaluator,anexceptionisthrown,whereas"10"wouldcoercetoanumeric 10. Coercion is always in
favorofthefieldtypeandnotthevaluetype:
Person(age=="10")//"10"iscoercedto10

5.8.3.3.4.CommaseparatedAND
The comma character (',') is used to separate constraint groups. It has implicit AND connective
semantics.
//Personisatleast50andweighsatleast80kg
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

31/56

9/4/2016

Chapter5.TheRuleLanguage

Person(age>50,weight>80)

//Personisatleast50,weighsatleast80kgandistallerthan2meter.
Person(age>50,weight>80,height>2)

Note
Althoughthe&&and,operatorshavethesamesemantics,theyareresolvedwithdifferent
priorities:The &&operatorprecedesthe || operator. Both the && and || operator precede
the,operator.Seetheoperatorprecedencelistbelow.
The comma operator should be preferred at the top level constraint, as it makes
constraintseasiertoreadandtheenginewilloftenbeabletooptimizethembetter.

The comma (,) operator cannot be embedded in a composite constraint expression, such as
parentheses:
Person((age>50,weight>80)||height>2)//DoNOTdothis:compileerror
//Usethisinstead
Person((age>50&&weight>80)||height>2)

5.8.3.3.5.Bindingvariables
Apropertycanbeboundtoavariable:
//2personsofthesameage
Person($firstAge:age)//binding
Person(age==$firstAge)//constraintexpression

Theprefixeddollarsymbol($)isjustaconventionitcanbeusefulincomplexruleswhereithelpsto
easilydifferentiatebetweenvariablesandfields.

Note
For backwards compatibility reasons, It's allowed (but not recommended) to mix a
constraintbindingandconstraintexpressionsassuch:
//Notrecommended
Person($age:age*2<100)

//Recommended(seperatesbindingsandconstraintexpressions)
Person(age*2<100,$age:age)

Boundvariablerestrictionsusingtheoperator ==provideforveryfastexecutionasitusehashindexing
toimproveperformance.

5.8.3.3.6.Unification
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

32/56

9/4/2016

Chapter5.TheRuleLanguage

Drools does not allow bindings to the same declaration. However this is an important aspect to
derivationqueryunification.Whilepositionalargumentsarealwaysprocessedwithunificationaspecial
unificationsymbol,':=',wasintroducedfornamedargumentsnamedarguments.Thefollowing"unifies"
theageargumentacrosstwopeople.
Person($age:=age)
Person($age:=age)

Inessenceunificationwilldeclareabindingforthefirstoccurance,andconstraintothesamevalueof
theboundfieldforsequenceoccurances.

5.8.3.3.7.Specialliteralsupport
BesidesnormalJavaliterals(includingJava5enums),thisliteralisalsosupported:

5.8.3.3.7.1.Dateliteral
Thedateformat ddmmmyyyyissupportedbydefault.Youcancustomizethisbyprovidinganalternative
dateformat mask as the System property named drools.dateformat. If more control is required, use a
restriction.

Example5.33.DateLiteralRestriction
Cheese(bestBefore<"27Oct2009")

5.8.3.3.8.ListandMapaccess
It'spossibletodirectlyaccessaListvaluebyindex:
//SameaschildList(0).getAge()==18
Person(childList[0].age==18)

It'salsopossibletodirectlyaccessaMapvaluebykey:
//SameascredentialMap.get("jsmith").isValid()
Person(credentialMap["jsmith"].valid)

5.8.3.3.9.Abbreviatedcombinedrelationcondition
Thisallowsyoutoplacemorethanonerestrictiononafieldusingtherestrictionconnectives && or ||.
Groupingviaparenthesesispermitted,resultinginarecursivesyntaxpattern.

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

33/56

9/4/2016

Chapter5.TheRuleLanguage

Figure5.14.Abbreviatedcombinedrelationcondition

Figure5.15.Abbreviatedcombinedrelationconditionwithparentheses

//Simpleabbreviatedcombinedrelationconditionusingasingle&&
Person(age>30&&<40)

//Complexabbreviatedcombinedrelationusinggroupings
Person(age((>30&&<40)||
(>20&&<25)))

//Mixingabbreviatedcombinedrelationwithconstraintconnectives
Person(age>30&&<40||location=="london")

5.8.3.3.10.SpecialDRLoperators

Figure5.16.Operators

Coerciontothecorrectvaluefortheevaluatorandthefieldwillbeattempted.

5.8.3.3.10.1.Theoperators < <= > >=

Theseoperatorscanbeusedonpropertieswithnaturalordering.Forexample,forDatefields, <means
before,forStringfields,itmeansalphabeticallylower.
Person(firstName<$otherFirstName)

Person(birthDate<$otherBirthDate)

OnlyappliesonComperableproperties.

5.8.3.3.10.2.Theoperator matches
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

34/56

9/4/2016

Chapter5.TheRuleLanguage

Matches a field against any valid Java Regular Expression. Typically that regexp is a string literal, but
variablesthatresolvetoavalidregexparealsoallowed.

Example5.34.RegularExpressionConstraint
Cheese(typematches"(Buffalo)?\\S*Mozarella")

Note
LikeinJava,regularexpressionswrittenasstringliteralsneedtoescape'\'.
Up to Drools 5.1 there was a configuration to support nonescaped regexps from Drools
4.0forbackwardscompatilibity.FromDrools5.2thisisnolongersupported.

OnlyappliesonStringproperties.

5.8.3.3.10.3.Theoperator notmatches

TheoperatorreturnstrueiftheStringdoesnotmatchtheregularexpression.Thesamerulesapplyas
forthematchesoperator.Example:

Example5.35.RegularExpressionConstraint
Cheese(typenotmatches"(Buffulo)?\\S*Mozarella")

OnlyappliesonStringproperties.

5.8.3.3.10.4.Theoperator contains

TheoperatorcontainsisusedtocheckwhetherafieldthatisaCollectionorarraycontainsthespecified
value.

Example5.36.ContainswithCollections
CheeseCounter(cheesescontains"stilton")//containswithaStringliteral
CheeseCounter(cheesescontains$var)//containswithavariable

OnlyappliesonCollectionproperties.

5.8.3.3.10.5.Theoperator notcontains
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

35/56

9/4/2016

Chapter5.TheRuleLanguage

TheoperatornotcontainsisusedtocheckwhetherafieldthatisaCollectionorarraydoesnotcontain
thespecifiedvalue.

Example5.37.LiteralConstraintwithCollections
CheeseCounter(cheesesnotcontains"cheddar")//notcontainswithaStringliteral
CheeseCounter(cheesesnotcontains$var)//notcontainswithavariable

OnlyappliesonCollectionproperties.

Note
Forbackwardcompatibility,the excludesoperatorissupportedasasynonym
fornotcontains.

5.8.3.3.10.6.Theoperator memberOf

TheoperatormemberOfisusedtocheckwhetherafieldisamemberofacollectionorarray.

Example5.38.LiteralConstraintwithCollections
CheeseCounter(cheesememberOf$matureCheeses)

Person(fathermemberOfparents)

5.8.3.3.10.7.Theoperator notmemberOf

TheoperatornotmemberOfisusedtocheckwhetherafieldisnotamemberofacollectionorarray.

Example5.39.LiteralConstraintwithCollections
CheeseCounter(cheesenotmemberOf$matureCheeses)

Person(fathernotmemberOfchildern)

5.8.3.3.10.8.Theoperator soundslike

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

36/56

9/4/2016

Chapter5.TheRuleLanguage

This operator is similar to matches, but it checks whether a word has almost the same sound (using
English pronunciation) as the given value. This is based on the Soundex algorithm (see
http://en.wikipedia.org/wiki/Soundex).

Example5.40.Testwithsoundslike
//matchcheese"fubar"or"foobar"
Cheese(namesoundslike'foobar')

5.8.3.3.10.9.Theoperator str

This operator str is used to check whether a field that is a String starts with or ends with a certain
value.ItcanalsobeusedtocheckthelengthoftheString.
Message(routingValuestr[startsWith]"R1")

Message(routingValuestr[endsWith]"R2")

Message(routingValuestr[length]17)

5.8.3.3.10.10.Theoperators inand notin(compoundvaluerestriction)

Thecompoundvaluerestrictionisusedwherethereismorethanonepossiblevaluetomatch.Currently
onlytheinandnotinevaluatorssupportthis.Thesecondoperandofthisoperatormustbeacomma
separated list of values, enclosed in parentheses. Values may be given as variables, literals, return
valuesorqualifiedidentifiers.Bothevaluatorsareactuallysyntacticsugar,internallyrewrittenasalistof
multiplerestrictionsusingtheoperators!=and==.

Figure5.17.compoundValueRestriction

Example5.41.CompoundRestrictionusing"in"
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

37/56

9/4/2016

Chapter5.TheRuleLanguage

Person($cheese:favouriteCheese)
Cheese(typein("stilton","cheddar",$cheese))

5.8.3.3.11.Inlineevaloperator(deprecated)

Figure5.18.InlineEvalExpression

Aninlineevalconstraintcanuseanyvaliddialectexpressionaslongasitresultstoaprimitiveboolean.
Theexpressionmustbeconstantovertime.Anypreviouslyboundvariable,fromthecurrentorprevious
pattern,canbeused.
Thisexamplewillfindallmalefemalepairswherethemaleis2yearsolderthanthefemalethevariable
ageisautocreatedinthesecondpatternbytheautovivificationprocess.

Example5.42.ReturnValueoperator
Person(girlAge:age,sex="F")
Person(eval(age==girlAge+2),sex='M')//eval()isactuallyobseleteinthisexample

Note
Inline eval's are effectively obsolete as their inner syntax is now directly supported. It's
recommended not to use them. Simply write the expression without wrapping eval()
aroundit.

5.8.3.3.12.Operatorprecedence
Theoperatorsareevaluatedinthisprecedence:
Table5.1.Operatorprecedence
Operatortype

Operators

Notes

(nested)
access

NotnormalJavasemantics

List/Mapaccess

[]

NotnormalJavasemantics

constraintbinding

NotnormalJavasemantics

multiplicative

*/%

additive

shift

<<>>>>>

relational

< > <= >=

property

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

38/56

9/4/2016

Chapter5.TheRuleLanguage

instanceof
==!=

DoesnotusenormalJava(not)same semantics: uses (not)


equalssemanticsinstead.

&

nonshort
circuiting
^
exclusiveOR

nonshort
circuiting
|
inclusiveOR

logicalAND

&&

logicalOR

||

ternary

?:

equality
nonshort
AND

circuiting

CommaseparatedAND ,

NotnormalJavasemantics

5.8.3.4.PositionalArguments
Patternsnowsupportpositionalargumentsontypedeclarations.
Positionalargumentsareoneswhereyoudon'tneedtospecifythefieldname,asthepositionmapstoa
known named field. i.e. Person( name == "mark" ) can be rewritten as Person( "mark" ). The
semicolon''isimportantsothattheengineknowsthateverythingbeforeitisapositional argument.
Otherwisewemightassumeitwasabooleanexpression,whichishowitcouldbeinterprettedafterthe
semicolon. You can mix positional and named arguments on a pattern by using the semicolon '' to
separatethem.Anyvariablesusedinapositionalthathavenotyetbeenboundwillbeboundtothefield
thatmapstothatposition.
declareCheese
name:String
shop:String
price:int
end

Examplepatterns,withtwoconstraintsandabinding.Remembersemicolon''isusedtodifferentiate
the positional section from the named argument section. Variables and literals and expressions using
just literals are supported in posional arguments, but not variables. Positional arguments are always
resolvedusingunification.
Cheese("stilton","CheeseShop",p;)
Cheese("stilton","CheeseShop";p:price)
Cheese("stilton";shop=="CheeseShop",p:price)
Cheese(name=="stilton";shop=="CheeseShop",p:price)

Positional arguments that are given a previously declared binding will consrain against that using
unificationthesearereferredtoasinputarguments.Ifthebindingdoesnotyetexist,itwillcreatethe
declarationbindingittothefieldrepresentedbythepositionargumentthesearereferredtoasoutput
arguments.

5.8.3.5.Basicconditionalelements

5.8.3.5.1.ConditionalElementand
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

39/56

9/4/2016

Chapter5.TheRuleLanguage

The Conditional Element "and" is used to group other Conditional Elements into a logical conjunction.
Droolssupportsbothprefixandandinfixand.

Figure5.19.infixAnd

Traditionalinfixandissupported:
//infixAnd
Cheese(cheeseType:type)andPerson(favouriteCheese==cheeseType)

Explicitgroupingwithparenthesesisalsosupported:
//infixAndwithgrouping
(Cheese(cheeseType:type)and
(Person(favouriteCheese==cheeseType)or
Person(favouriteCheese==cheeseType))

Note
Thesymbol&&(asanalternativetoand)isdeprecated.Butitisstillsupportedinthesyntax
forbackwardscompatibility.

Figure5.20.prefixAnd

Prefixandisalsosupported:
(andCheese(cheeseType:type)
Person(favouriteCheese==cheeseType))

TherootelementoftheLHSisanimplicitprefixandanddoesn'tneedtobespecified:

Example5.43.implicitrootprefixAnd
when
Cheese(cheeseType:type)
Person(favouriteCheese==cheeseType)
then
...

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

40/56

9/4/2016

Chapter5.TheRuleLanguage

5.8.3.5.2.ConditionalElementor
TheConditionalElementorisusedtogroupotherConditionalElementsintoalogicaldisjunction.Drools
supportsbothprefixorandinfixor.

Figure5.21.infixOr

Traditionalinfixorissupported:
//infixOr
Cheese(cheeseType:type)orPerson(favouriteCheese==cheeseType)

Explicitgroupingwithparenthesesisalsosupported:
//infixOrwithgrouping
(Cheese(cheeseType:type)or
(Person(favouriteCheese==cheeseType)and
Person(favouriteCheese==cheeseType))

Note
Thesymbol||(asanalternativetoor)isdeprecated.Butitisstillsupportedinthesyntax
forbackwardscompatibility.

Figure5.22.prefixOr

Prefixorisalsosupported:
(orPerson(sex=="f",age>60)
Person(sex=="m",age>65)

Note
The behavior of the Conditional Element or is different from the connective || for
constraintsandrestrictionsinfieldconstraints.Theengineactuallyhasnounderstanding
oftheConditionalElement or.Instead,viaanumberofdifferentlogictransformations, a
rulewithorisrewrittenasanumberofsubrules.Thisprocessultimatelyresultsinarule
thathasasingleorastherootnodeandonesubruleforeachofitsCEs.Eachsubrulecan
activateandfirelikeanynormalrulethereisnospecialbehaviororinteractionbetween
thesesubrules.Thiscanbemostconfusingtonewruleauthors.
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

41/56

9/4/2016

Chapter5.TheRuleLanguage

The Conditional Element or also allows for optional pattern binding. This means that each resulting
subrule will bind its pattern to the pattern binding. Each pattern must be bound separately, using
eponymousvariables:
pensioner:(Person(sex=="f",age>60)orPerson(sex=="m",age>65))

(orpensioner:Person(sex=="f",age>60)
pensioner:Person(sex=="m",age>65))

Since the conditional element or results in multiple subrule generation, one for each possible logically
outcome,theexampleabovewouldresultintheinternalgenerationoftworules.Thesetworuleswork
independentlywithintheWorkingMemory,whichmeansbothcanmatch,activateandfirethereisno
shortcutting.
Thebestwaytothinkoftheconditionalelement orisasashortcutforgeneratingtwoormoresimilar
rules.Whenyouthinkofitthatway,it'sclearthatforasingleruletherecouldbemultipleactivationsif
twoormoretermsofthedisjunctionaretrue.

5.8.3.5.3.ConditionalElementnot

Figure5.23.not

TheCEnotisfirstorderlogic'snonexistentialquantifierandchecksforthenonexistenceofsomething
intheWorkingMemory.Thinkof"not"asmeaning"theremustbenoneof...".
ThekeywordnotmaybefollowedbyparenthesesaroundtheCEsthatitappliesto.Inthesimplestcase
ofasinglepattern(likebelow)youmayoptionallyomittheparentheses.

Example5.44.NoBusses
notBus()

Example5.45.NoredBusses
//Bracketsareoptional:
notBus(color=="red")
//Bracketsareoptional:
not(Bus(color=="red",number==42))
//"not"withnestedinfixandtwopatterns,
//bracketsarerequires:
not(Bus(color=="red")and
Bus(color=="blue"))
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

42/56

9/4/2016

Chapter5.TheRuleLanguage

5.8.3.5.4.ConditionalElementexists

Figure5.24.exists

TheCEexistsisfirstorderlogic'sexistentialquantifierandchecksfortheexistenceofsomethinginthe
WorkingMemory.Thinkof"exists"asmeaning"thereisatleastone..".Itisdifferentfromjusthaving
thepatternonitsown,whichismorelikesaying"foreachoneof...".Ifyouuse existswithapattern,
therulewillonlyactivateatmostonce,regardlessofhowmuchdatathereisinworkingmemorythat
matchestheconditioninsideoftheexistspattern.Sinceonlytheexistencematters,nobindingswillbe
established.
ThekeywordexistsmustbefollowedbyparenthesesaroundtheCEsthatitappliesto.Inthesimplest
caseofasinglepattern(likebelow)youmayomittheparentheses.

Example5.46.AtleastoneBus
existsBus()

Example5.47.AtleastoneredBus
existsBus(color=="red")
//bracketsareoptional:
exists(Bus(color=="red",number==42))
//"exists"withnestedinfixand,
//bracketsarerequired:
exists(Bus(color=="red")and
Bus(color=="blue"))

5.8.3.6.Advancedconditionalelements

5.8.3.6.1.ConditionalElementforall

Figure5.25.forall

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

43/56

9/4/2016

Chapter5.TheRuleLanguage

The Conditional Element forall completes the First Order Logic support in Drools. The Conditional
Element forall evaluates to true when all facts that match the first pattern match all the remaining
patterns.Example:
rule"AllEnglishbusesarered"
when
forall($bus:Bus(type=='english')
Bus(this==$bus,color='red'))
then
#allenglishbusesarered
end

Intheaboverule,we"select"allBusobjectswhosetypeis"english".Then,foreachfactthatmatches
thispatternweevaluatethefollowingpatternsandiftheymatch,theforallCEwillevaluatetotrue.
Tostatethatallfactsofagiventypeintheworkingmemorymustmatchasetofconstraints, forall
canbewrittenwithasinglepatternforsimplicity.Example:

Example5.48.SinglePatternForall
rule"AllBusesareRed"
when
forall(Bus(color=='red'))
then
#allassertedBusfactsarered
end

Anotherexampleshowsmultiplepatternsinsidetheforall:

Example5.49.MultiPatternForall
rule"allemployeeshavehealthanddentalcareprograms"
when
forall($emp:Employee()
HealthCare(employee==$emp)
DentalCare(employee==$emp)
)
then
#allemployeeshavehealthanddentalcare
end

ForallcanbenestedinsideotherCEs.Forinstance, forallcanbeusedinsidea notCE.Notethatonly


singlepatternshaveoptionalparentheses,sothatwithanestedforallparenthesesmustbeused:

Example5.50.CombiningForallwithNotCE
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

44/56

9/4/2016

Chapter5.TheRuleLanguage

rule"notallemployeeshavehealthanddentalcare"
when
not(forall($emp:Employee()
HealthCare(employee==$emp)
DentalCare(employee==$emp))
)
then
#notallemployeeshavehealthanddentalcare
end

Asasidenote,forall(p1p2p3...)isequivalenttowriting:
not(p1andnot(andp2p3...))

Also,itisimportanttonotethat forallisascopedelimiter.Therefore,itcanuseanypreviouslybound
variable,butnovariableboundinsideitwillbeavailableforuseoutsideofit.

5.8.3.6.2.ConditionalElementfrom

Figure5.26.from

TheConditionalElementfromenablesuserstospecifyanarbitrarysourcefordatatobematchedbyLHS
patterns.ThisallowstheenginetoreasonoverdatanotintheWorkingMemory.Thedatasourcecould
be a subfield on a bound variable or the results of a method call. It is a powerful construction that
allows out of the box integration with other application components and frameworks. One common
example is the integration with data retrieved ondemand from databases using hibernate named
queries.
The expression used to define the object source is any expression that follows regular MVEL syntax.
Therefore,itallowsyoutoeasilyuseobjectpropertynavigation,executemethodcallsandaccessmaps
andcollectionselements.
Hereisasimpleexampleofreasoningandbindingonanotherpatternsubfield:
rule"validatezipcode"
when
Person($personAddress:address)
Address(zipcode=="23920W")from$personAddress
then
#zipcodeisok
end

With all the flexibility from the new expressiveness in the Drools engine you can slice and dice this
problemmanyways.Thisisthesamebutshowshowyoucanuseagraphnotationwiththe'from':
rule"validatezipcode"
when
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

45/56

9/4/2016

Chapter5.TheRuleLanguage

$p:Person()
$a:Address(zipcode=="23920W")from$p.address
then
#zipcodeisok
end

Previousexampleswereevaluationsusingasinglepattern.TheCEfromalsosupportobjectsourcesthat
returnacollectionofobjects.Inthatcase, fromwilliterate over all objects in the collection and try to
matcheachofthemindividually.Forinstance,ifwewantarulethatapplies10%discounttoeachitem
inanorder,wecoulddo:
rule"apply10%discounttoallitemsoverUS$100,00inanorder"
when
$order:Order()
$item:OrderItem(value>100)from$order.items
then
#applydiscountto$item
end

Theaboveexamplewillcausetheruletofireonceforeachitemwhose value is greater than 100 for


eachgivenorder.
Youmusttakecaution,however,whenusingfrom,especiallyinconjunctionwiththelockonactiverule
attributeasitmayproduceunexpectedresults.Considertheexampleprovidedearlier,butnowslightly
modifiedasfollows:
rule"AssignpeopleinNorthCarolina(NC)tosalesregion1"
ruleflowgroup"test"
lockonactivetrue
when
$p:Person()
$a:Address(state=="NC")from$p.address
then
modify($p){}#Assignpersontosalesregion1inamodifyblock
end
rule"ApplyadiscounttopeopleinthecityofRaleigh"
ruleflowgroup"test"
lockonactivetrue
when
$p:Person()
$a:Address(city=="Raleigh")from$p.address
then
modify($p){}#Applydiscounttopersoninamodifyblock
end

In the above example, persons in Raleigh, NC should be assigned to sales region 1 and receive a
discounti.e.,youwouldexpectbothrulestoactivateandfire.Insteadyouwillfindthatonlythesecond
rulefires.
Ifyouweretoturnontheauditlog,youwouldalsoseethatwhenthesecondrulefires,itdeactivates
thefirstrule.Sincetheruleattributelockonactivepreventsarulefromcreatingnewactivationswhen
asetoffactschange,thefirstrulefailstoreactivate.Thoughthesetoffactshavenotchanged,theuse
offromreturnsanewfactforallintentsandpurposeseachtimeitisevaluated.
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

46/56

9/4/2016

Chapter5.TheRuleLanguage

First,it'simportanttoreviewwhyyouwouldusetheabovepattern.Youmayhavemanyrulesacross
different ruleflow groups. When rules modify working memory and other rules downstream of your
RuleFlow(indifferentruleflowgroups)needtobereevaluated,theuseof modify is critical. You don't,
however,wantotherrulesinthesameruleflowgrouptoplaceactivationsononeanotherrecursively.
In this case, the noloop attribute is ineffective, as it would only prevent a rule from activating itself
recursively.Hence,youresorttolockonactive.
Thereareseveralwaystoaddressthisissue:
Avoid the use of from when you can assert all facts into working memory or use nested object
referencesinyourconstraintexpressions(shownbelow).
Placethevariableassignedusedinthemodifyblockasthelastsentenceinyourcondition(LHS).
Avoidtheuseoflockonactivewhenyoucanexplicitlymanagehowruleswithinthesameruleflow
groupplaceactivationsononeanother(explainedbelow).
The preferred solution is to minimize use of from when you can assert all your facts into working
memory directly. In the example above, both the Person and Address instance can be asserted into
workingmemory.Inthiscase,becausethegraphisfairlysimple,aneveneasiersolutionistomodify
yourrulesasfollows:
rule"AssignpeopleinNorthCarolina(NC)tosalesregion1"
ruleflowgroup"test"
lockonactivetrue
when
$p:Person(address.state=="NC")
then
modify($p){}#Assignpersontosalesregion1inamodifyblock
end
rule"ApplyadiscounttopeopleinthecityofRaleigh"
ruleflowgroup"test"
lockonactivetrue
when
$p:Person(address.city=="Raleigh")
then
modify($p){}#Applydiscounttopersoninamodifyblock
end

Now,youwillfindthatbothrulesfireasexpected.However,itisnotalwayspossibletoaccessnested
factsasabove.ConsideranexamplewhereaPersonholdsoneormoreAddressesandyouwishtouse
anexistentialquantifiertomatchpeoplewithatleastoneaddressthatmeetscertainconditions.Inthis
case,youwouldhavetoresorttotheuseoffromtoreasonoverthecollection.
Thereareseveralwaystouse fromtoachievethisandnotallofthemexhibitanissuewiththeuseof
lockonactive.Forexample,thefollowinguseoffromcausesbothrulestofireasexpected:
rule"AssignpeopleinNorthCarolina(NC)tosalesregion1"
ruleflowgroup"test"
lockonactivetrue
when
$p:Person($addresses:addresses)
exists(Address(state=="NC")from$addresses)
then
modify($p){}#Assignpersontosalesregion1inamodifyblock
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

47/56

9/4/2016

Chapter5.TheRuleLanguage

end
rule"ApplyadiscounttopeopleinthecityofRaleigh"
ruleflowgroup"test"
lockonactivetrue
when
$p:Person($addresses:addresses)
exists(Address(city=="Raleigh")from$addresses)
then
modify($p){}#Applydiscounttopersoninamodifyblock
end

However,thefollowingslightlydifferentapproachdoesexhibittheproblem:
rule"AssignpeopleinNorthCarolina(NC)tosalesregion1"
ruleflowgroup"test"
lockonactivetrue
when
$assessment:Assessment()
$p:Person()
$addresses:List()from$p.addresses
exists(Address(state=="NC")from$addresses)
then
modify($assessment){}#Modifyassessmentinamodifyblock
end
rule"ApplyadiscounttopeopleinthecityofRaleigh"
ruleflowgroup"test"
lockonactivetrue
when
$assessment:Assessment()
$p:Person()
$addresses:List()from$p.addresses
exists(Address(city=="Raleigh")from$addresses)
then
modify($assessment){}#Modifyassessmentinamodifyblock
end

In the above example, the $addresses variable is returned from the use of from. The example also
introducesanewobject,assessment,tohighlightonepossiblesolutioninthiscase.Ifthe$assessment
variable assigned in the condition (LHS) is moved to the last condition in each rule, both rules fire as
expected.
Thoughtheaboveexamplesdemonstratehowtocombinetheuseoffromwithlockonactivewhereno
loss of rule activations occurs, they carry the drawback of placing a dependency on the order of
conditionsontheLHS.Inaddition,thesolutionspresentgreatercomplexityfortheruleauthorinterms
ofkeepingtrackofwhichconditionsmaycreateissues.
Abetteralternativeistoassertmorefactsintoworkingmemory.Inthiscase,aperson'saddressesmay
beassertedintoworkingmemoryandtheuseoffromwouldnotbenecessary.
Therearecases,however,whereassertingalldataintoworkingmemoryisnotpracticalandweneedto
find other solutions. Another option is to reevaluate the need for lockonactive. An alternative to
lockonactiveistodirectlymanagehowruleswithinthesameruleflowgroupactivateoneanotherby

includingconditionsineachrulethatpreventrulesfromactivatingeachotherrecursivelywhenworking
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

48/56

9/4/2016

Chapter5.TheRuleLanguage

memoryismodified.Forexample,inthecaseabovewhereadiscountisappliedtocitizensofRaleigh,a
conditionmaybeaddedtotherulethatcheckswhetherthediscounthasalreadybeenapplied.Ifso,the
ruledoesnotactivate.

5.8.3.6.3.ConditionalElementcollect

Figure5.27.collect

The Conditional Element collect allows rules to reason over a collection of objects obtained from the
givensourceorfromtheworkingmemory.InFirstOderLogictermsthisisthecardinalityquantifier.A
simpleexample:
importjava.util.ArrayList
rule"Raisepriorityifsystemhasmorethan3pendingalarms"
when
$system:System()
$alarms:ArrayList(size>=3)
fromcollect(Alarm(system==$system,status=='pending'))
then
#Raisepriority,becausesystem$systemhas
#3ormorealarmspending.Thependingalarms
#are$alarms.
end

Intheaboveexample,therulewilllookforallpendingalarmsin the working memory for each given


systemandgrouptheminArrayLists.If3ormorealarmsarefoundforagivensystem,therulewillfire.
The result pattern of collect can be any concrete class that implements the java.util.Collection
interfaceandprovidesadefaultnoargpublicconstructor.ThismeansthatyoucanuseJavacollections
like ArrayList, LinkedList, HashSet, etc., or your own class, as long as it implements the
java.util.Collectioninterfaceandprovideadefaultnoargpublicconstructor.

Bothsourceandresultpatternscanbeconstrainedasanyotherpattern.
VariablesboundbeforethecollectCEareinthescopeofbothsourceandresultpatternsandtherefore
youcanusethemtoconstrainbothyoursourceandresultpatterns.Butnotethat collectisascope
delimiterforbindings,sothatanybindingmadeinsideofitisnotavailableforuseoutsideofit.
CollectacceptsnestedfromCEs.Thefollowingexampleisavaliduseof"collect":
importjava.util.LinkedList;
rule"Sendamessagetoallmothers"
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

49/56

9/4/2016

Chapter5.TheRuleLanguage

when
$town:Town(name=='Paris')
$mothers:LinkedList()
fromcollect(Person(gender=='F',children>0)
from$town.getPeople()
)
then
#sendamessagetoallmothers
end

5.8.3.6.4.ConditionalElementaccumulate

Figure5.28.accumulate

TheConditionalElement accumulateisamoreflexibleandpowerfulformof collect,inthesensethatit


canbeusedtodowhatcollectdoesandalsoachieveresultsthattheCEcollectisnotcapableofdoing.
Basically, what it does is that it allows a rule to iterate over a collection of objects, executing custom
actionsforeachoftheelements,andattheenditreturnsaresultobject.
Accumulate supports both the use of predefined accumulate functions, or the use of inline custom
code.Inlinecustomcodeshouldbeavoidedthough,asitisextremelyhardtomaintain,andfrequently
leadstocodeduplication.Accumulatefunctionsareeasiertotestandreuse.

5.8.3.6.4.1.AccumulateFunctions
The accumulate CE is a very powerful CE, but it gets real declarative and easy to use when using
predefinedfunctionsthatareknownasAccumulateFunctions.Theyworkexactlylikeaccumulate,but
insteadofexplicitlywritingcustomcodeineveryaccumulateCE,theusercanusepredefinedcodefor
commonoperations.
Forinstance,aruletoapplya10%discountonordersover$100couldbewritteninthefollowingway,
usingAccumulateFunctions:
rule"Apply10%discounttoordersoverUS$100,00"
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

50/56

9/4/2016

Chapter5.TheRuleLanguage

when
$order:Order()
$total:Number(doubleValue>100)
fromaccumulate(OrderItem(order==$order,$value:value),
sum($value))
then
#applydiscountto$order
end

Intheaboveexample,sumisanAccumulateFunctionandwillsumthe$valueofallOrderItemsand
returntheresult.
Droolsshipswiththefollowingbuiltinaccumulatefunctions:
average
min
max
count
sum
collectList
collectSet
These common functions accept any expression as input. For instance, if someone wants to calculate
theaverageprofitonallitemsofanorder,arulecouldbewrittenusingtheaveragefunction:
rule"Averageprofit"
when
$order:Order()
$profit:Number()
fromaccumulate(OrderItem(order==$order,$cost:cost,$price:price)
average(1$cost/$price))
then
#averageprofitfor$orderis$profit
end

AccumulateFunctionsareallpluggable.Thatmeansthatifneeded, custom, domain specific functions


can easily be added to the engine and rules can start to use them without any restrictions. To
implementanewAccumulateFunctionsalloneneedstodoistocreateaJavaclassthatimplements
the org.drools.runtime.rule.TypedAccumulateFunctioninterface and add a line to the configuration file or
setasystempropertytolettheengineknowaboutthenewfunction.AsanexampleofanAccumulate
Functionimplementation,thefollowingistheimplementationoftheaveragefunction:
/**
*Animplementationofanaccumulatorcapableofcalculatingaveragevalues
*/
publicclassAverageAccumulateFunctionimplementsAccumulateFunction{
publicvoidreadExternal(ObjectInputin)throwsIOException,ClassNotFoundException{
}
publicvoidwriteExternal(ObjectOutputout)throwsIOException{
}
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

51/56

9/4/2016

Chapter5.TheRuleLanguage

publicstaticclassAverageDataimplementsExternalizable{
publicintcount=0;
publicdoubletotal=0;

publicAverageData(){}
publicvoidreadExternal(ObjectInputin)throwsIOException,ClassNotFoundException{
count=in.readInt();
total=in.readDouble();
}
publicvoidwriteExternal(ObjectOutputout)throwsIOException{
out.writeInt(count);
out.writeDouble(total);
}
}
/*(nonJavadoc)
*@seeorg.drools.base.accumulators.AccumulateFunction#createContext()
*/
publicSerializablecreateContext(){
returnnewAverageData();
}
/*(nonJavadoc)
*@seeorg.drools.base.accumulators.AccumulateFunction#init(java.lang.Object)
*/
publicvoidinit(Serializablecontext)throwsException{
AverageDatadata=(AverageData)context;
data.count=0;
data.total=0;
}
/*(nonJavadoc)
*@seeorg.drools.base.accumulators.AccumulateFunction#accumulate(java.lang.Object,java.lang.Object)
*/
publicvoidaccumulate(Serializablecontext,
Objectvalue){
AverageDatadata=(AverageData)context;
data.count++;
data.total+=((Number)value).doubleValue();
}
/*(nonJavadoc)
*@seeorg.drools.base.accumulators.AccumulateFunction#reverse(java.lang.Object,java.lang.Object)
*/
publicvoidreverse(Serializablecontext,
Objectvalue)throwsException{
AverageDatadata=(AverageData)context;
data.count;
data.total=((Number)value).doubleValue();
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

52/56

9/4/2016

Chapter5.TheRuleLanguage

data.total=((Number)value).doubleValue();
}
/*(nonJavadoc)

*@seeorg.drools.base.accumulators.AccumulateFunction#getResult(java.lang.Object)
*/
publicObjectgetResult(Serializablecontext)throwsException{
AverageDatadata=(AverageData)context;
returnnewDouble(data.count==0?0:data.total/data.count);
}
/*(nonJavadoc)
*@seeorg.drools.base.accumulators.AccumulateFunction#supportsReverse()
*/
publicbooleansupportsReverse(){
returntrue;
}
/**
*{@inheritDoc}
*/
publicClass<?>getResultType(){
returnNumber.class;
}
}

Thecodeforthefunctionisverysimple,aswecouldexpect,asallthe"dirty"integrationworkisdone
bytheengine.Finally,toplugthefunctionintotheengine,weaddedittotheconfigurationfile:
drools.accumulate.function.average=
org.drools.base.accumulators.AverageAccumulateFunction

Here,"drools.accumulate.function."isaprefixthatmustalwaysbeused,"average"ishowthefunction
willbeusedintherulefile,and"org.drools.base.accumulators.AverageAccumulateFunction"isthefully
qualifiednameoftheclassthatimplementsthefunctionbehavior.

5.8.3.6.4.2.Accumulatewithinlinecustomcode

Warning
Theuseofaccumulatewithinlinecustomcodeisnotagoodpracticeforseveralreasons,
includingdificultiesonmaintainingandtestingrulesthatusethem,aswellastheinability
of reusing that code. Implementing your own accumulate functions is very simple and
straightforward, they are easy to unit test and to use. This form of accumulate is
supportedforbackwardcompatibilityonly.

ThegeneralsyntaxoftheaccumulateCEwithinlinecustomcodeis:
<resultpattern>fromaccumulate(<sourcepattern>,
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

53/56

9/4/2016

Chapter5.TheRuleLanguage

init(<initcode>),
action(<actioncode>),
reverse(<reversecode>),
result(<resultexpression>))

Themeaningofeachoftheelementsisthefollowing:
<sourcepattern>:thesourcepatternisaregularpatternthattheenginewilltrytomatchagainst
eachofthesourceobjects.
<initcode>:thisisasemanticblock of code in the selected dialect that will be executed once for
eachtuple,beforeiteratingoverthesourceobjects.
<actioncode>:thisisasemanticblockofcodeintheselecteddialectthatwillbeexecutedforeach
ofthesourceobjects.
<reversecode>:thisisanoptionalsemanticblockofcodeintheselecteddialectthatifpresentwill
beexecutedforeachsourceobjectthatnolongermatchesthesourcepattern.Theobjectiveofthis
codeblockisto undo any calculation done in the <actioncode> block, so that the engine can do
decrementalcalculationwhenasourceobjectismodifiedorretracted,hugelyimprovingperformance
oftheseoperations.
<resultexpression>:thisisasemanticexpressionintheselecteddialectthatisexecutedafter all
sourceobjectsareiterated.
<resultpattern>:thisisaregularpatternthattheenginetriestomatchagainsttheobjectreturned
from the <resultexpression>. If it matches, the accumulate conditional element evaluates to true
andtheengineproceedswiththeevaluationofthenextCEintherule.Ifitdoesnotmatches,the
accumulateCEevaluatestofalseandtheenginestopsevaluatingCEsforthatrule.
Itiseasiertounderstandifwelookatanexample:
rule"Apply10%discounttoordersoverUS$100,00"
when
$order:Order()
$total:Number(doubleValue>100)
fromaccumulate(OrderItem(order==$order,$value:value),
init(doubletotal=0;),
action(total+=$value;),
reverse(total=$value;),
result(total))
then
#applydiscountto$order
end

In the above example, for each Order in the Working Memory, the engine will execute the init code
initializing the total variable to zero. Then it will iterate over all OrderItem objects for that order,
executing the action for each one (in the example, it will sum the value of all items into the total
variable). After iterating over all OrderItem objects, it will return the value corresponding to the result
expression(intheaboveexample,thevalueofvariable total).Finally,theenginewilltrytomatchthe
resultwiththeNumberpattern,andifthedoublevalueisgreaterthan100,therulewillfire.
TheexampleusedJavaasthesemanticdialect,andassuch,notethattheusageofthesemicolonas
statementdelimiterismandatoryintheinit,actionandreversecodeblocks.Theresultisanexpression
and,assuch,itdoesnotadmit''.Iftheuserusesanyotherdialect,hemustcomplytothatdialect's
specificsyntax.
Asmentionedbefore,thereversecodeisoptional,butitisstronglyrecommendedthattheuserwritesit
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

54/56

9/4/2016

Chapter5.TheRuleLanguage

inordertobenefitfromtheimprovedperformanceonupdateandretract.
The accumulate CE can be used to execute any action on source objects. The following example
instantiatesandpopulatesacustomobject:
rule"Accumulateusingcustomobjects"
when
$person:Person($likes:likes)
$cheesery:Cheesery(totalAmount>100)
fromaccumulate($cheese:Cheese(type==$likes),
init(Cheeserycheesery=newCheesery();),
action(cheesery.addCheese($cheese);),
reverse(cheesery.removeCheese($cheese);),
result(cheesery));
then
//dosomething
end

5.8.3.6.4.3.MultifunctionAccumulates
TheaccumulateCEnowsupportsmultiplefunctions.Forinstance, if one needs to find the minimum,
maximum and average value for the same set of data, instead of having to repeat the accumulate
statement3times,asingleaccumulatecanbeused.
rule"Max,minandaverage"
when
accumulate(Cheese($price:price),
$max:max($price),
$min:min($price),
$avg:average($price))
then
//dosomething
end

5.8.3.7.ConditionalElement eval

Figure5.29.eval

Theconditionalelement eval is essentially a catchall which allows any semantic code (that returns a
primitiveboolean)tobeexecuted.Thiscodecanrefertovariablesthatwerebound in the LHS of the
rule,andfunctionsintherulepackage.Overuseofevalreducesthedeclarativenessofyourrulesand
can result in a poorly performing engine. While eval can be used anywhere in the patterns, the best
practiceistoadditasthelastconditionalelementintheLHSofarule.
Evals cannot be indexed and thus are not as efficient as Field Constraints. However this makes them
ideal for being used when functions return values that change over time, which is not allowed within
FieldConstraints.
https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

55/56

9/4/2016

Chapter5.TheRuleLanguage

For folks who are familiar with Drools 2.x lineage, the old Drools parameter and condition tags are
equivalenttobindingavariabletoanappropriatetype,andthenusingitinanevalnode.
p1:Parameter()
p2:Parameter()
eval(p1.getList().containsKey(p2.getItem()))

p1:Parameter()
p2:Parameter()
//callfunctionisValidintheLHS
eval(isValid(p1,p2))

5.8.3.8.Railroaddiagrams
AccumulateAction
Statement
action

,
)

https://docs.jboss.org/drools/release/5.2.0.Final/droolsexpertdocs/html/ch05.html

56/56

You might also like