Professional Documents
Culture Documents
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
Youmayavoidhavingtowritethefullyqualifiednameofaclasseverytimeyouwriteitbyusingthe
importclause,aspreviouslydiscussed.
Example5.12.Avoidingtheneedtousefullyqualifiedclassnamesbyusingimport
importjava.util.Date
declarePerson
name:String
dateOfBirth:Date
address:Address
end
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.
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)
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
==!=
&
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
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
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
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
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
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