<br><font size=2 face="sans-serif">Hello,</font>
<br>
<br><font size=2 face="sans-serif">Again, I'm working on converting my
project that used Drools 4.0.7 to 5.0.1.</font>
<br>
<br><font size=2 face="sans-serif">I've run across a problem with a rule
that accesses a map in the LHS using a variable as the key. When
MVEL tries to resolve this, it appears that it is not evaluating the variable
before accessing the map. I've modified the Shopping example from
the Drools 5.0.1 Examples to recreate the issue in a simpler setting.</font>
<br>
<br><font size=2 face="sans-serif">This is the rule (I removed all the
other rules for this example)</font>
<br><font size=2 face="Courier New"><b>rule</b> "Cart notification"</font>
<br><font size=2 face="Courier New"> <b>salience</b> 10</font>
<br>
<br><font size=2 face="Courier New"> <b>when</b></font>
<br><font size=2 face="Courier New"> $p : Product(
$productName : name)</font>
<br><font size=2 face="Courier New"> $c : Customer(
cart[$productName] == $p) </font>
<br><font size=2 face="Courier New"> <b>then</b></font>
<br><font size=2 face="Courier New"> System.out.println(
"Customer " + $c.name + " has " + $p.name + "
in cart");</font>
<br><font size=2 face="Courier New"><b>end</b> </font>
<br>
<br><font size=2 face="sans-serif">I added the following to the Customer
class:</font>
<br>
<br><font size=2 face="Courier New"><b>private</b> Map<String,Product>
cart = <b>new</b> HashMap<String, Product>();</font>
<br><font size=2 face="Courier New"><b>public</b> Map<String, Product>
getCart() {</font>
<br><font size=2 face="Courier New"> <b>return</b> cart;</font>
<br><font size=2 face="Courier New">}</font>
<br>
<br><font size=2 face="Courier New">and I modified the main method to be:</font>
<br>
<br><font size=2 face="Courier New"><b>public</b> <b>static</b> <b>final</b>
<b>void</b> main(String[] args) <b>throws</b> Exception {</font>
<br><font size=2 face="Courier New"> <b>final</b> KnowledgeBuilder
kbuilder = KnowledgeBuilderFactory.<i>newKnowledgeBuilder</i>();</font>
<br><font size=2 face="Courier New"> kbuilder.add( ResourceFactory.<i>newClassPathResource</i>(
"Shopping.drl", ShoppingExample.<b>class</b> ),</font>
<br><font size=2 face="Courier New">
ResourceType.<i>DRL</i>
);</font>
<br>
<br><font size=2 face="Courier New"> <b>final</b> KnowledgeBase
kbase = KnowledgeBaseFactory.<i>newKnowledgeBase</i>();</font>
<br><font size=2 face="Courier New"> kbase.addKnowledgePackages(
kbuilder.getKnowledgePackages() );</font>
<br>
<br><font size=2 face="Courier New"> <b>final</b> StatefulKnowledgeSession
ksession = kbase.newStatefulKnowledgeSession();</font>
<br>
<br><font size=2 face="Courier New"> Customer mark = <b>new</b>
Customer( "mark",</font>
<br><font size=2 face="Courier New">
0 );</font>
<br><font size=2 face="Courier New"> ksession.insert( mark
);</font>
<br>
<br><font size=2 face="Courier New"> Product shoes = <b>new</b>
Product( "shoes",</font>
<br><font size=2 face="Courier New">
60 );</font>
<br><font size=2 face="Courier New"> ksession.insert( shoes
);</font>
<br><font size=2 face="Courier New"> </font>
<br><font size=2 face="Courier New"> mark.getCart().put("shoes",
shoes);</font>
<br><font size=2 face="Courier New"> </font>
<br><font size=2 face="Courier New"> <u>ksession</u>.fireAllRules();</font>
<br><font size=2 face="Courier New">}</font>
<br>
<br><font size=2 face="sans-serif">So basically, I added a map to Customer,
inserted one item and made a rule that will use a variable as a key for
that map. </font>
<br><font size=2 face="sans-serif">What I would expect to happen is:</font>
<br><font size=2 face="sans-serif"> the Product pattern would match
the shoes Product that is inserted into the ksession, the $productName
variable would contain the value "shoes"</font>
<br><font size=2 face="sans-serif"> the Customer fact, mark, would
be matched with the second pattern in the rule because cart["shoes"]
should resolve to the shoes fact which is $p in the rule</font>
<br><font size=2 face="sans-serif"> The message should print</font>
<br>
<br><font size=2 face="sans-serif">What actually happens is an error message:</font>
<br>
<br><font size=2 face="Courier New">Exception in thread "main"
<u>org.drools.RuntimeDroolsException</u>: Exception executing predicate
cart[$productName] == $p</font>
<br><font size=2 face="Courier New"> at
org.drools.rule.PredicateConstraint.isAllowedCachedLeft(<u>PredicateConstraint.java:302</u>)</font>
<br><font size=2 face="Courier New"> at
org.drools.common.SingleBetaConstraints.isAllowedCachedLeft(<u>SingleBetaConstraints.java:138</u>)</font>
<br><font size=2 face="Courier New"> at
org.drools.reteoo.JoinNode.assertLeftTuple(<u>JoinNode.java:114</u>)</font>
<br><font size=2 face="Courier New"> at
org.drools.reteoo.SingleLeftTupleSinkAdapter.doPropagateAssertLeftTuple(<u>SingleLeftTupleSinkAdapter.java:117</u>)</font>
<br><font size=2 face="Courier New"> at
org.drools.reteoo.SingleLeftTupleSinkAdapter.createAndPropagateAssertLeftTuple(<u>SingleLeftTupleSinkAdapter.java:78</u>)</font>
<br><font size=2 face="Courier New"> at
org.drools.reteoo.LeftInputAdapterNode.assertObject(<u>LeftInputAdapterNode.java:142</u>)</font>
<br><font size=2 face="Courier New"> at
org.drools.reteoo.SingleObjectSinkAdapter.propagateAssertObject(<u>SingleObjectSinkAdapter.java:42</u>)</font>
<br><font size=2 face="Courier New"> at
org.drools.reteoo.ObjectTypeNode.assertObject(<u>ObjectTypeNode.java:185</u>)</font>
<br><font size=2 face="Courier New"> at
org.drools.reteoo.EntryPointNode.assertObject(<u>EntryPointNode.java:146</u>)</font>
<br><font size=2 face="Courier New"> at
org.drools.common.AbstractWorkingMemory.insert(<u>AbstractWorkingMemory.java:1046</u>)</font>
<br><font size=2 face="Courier New"> at
org.drools.common.AbstractWorkingMemory.insert(<u>AbstractWorkingMemory.java:1001</u>)</font>
<br><font size=2 face="Courier New"> at
org.drools.common.AbstractWorkingMemory.insert(<u>AbstractWorkingMemory.java:788</u>)</font>
<br><font size=2 face="Courier New"> at
org.drools.impl.StatefulKnowledgeSessionImpl.insert(<u>StatefulKnowledgeSessionImpl.java:216</u>)</font>
<br><font size=2 face="Courier New"> at
org.drools.examples.ShoppingExample.main(<u>ShoppingExample.java:32</u>)</font>
<br><font size=2 face="Courier New">Caused by: [Error: unable to resolve
method: java.util.HashMap.$productName() [arglength=0]]</font>
<br><font size=2 face="Courier New">[Near : {... Unknown ....}]</font>
<br><font size=2 face="Courier New">
^</font>
<br><font size=2 face="Courier New">[Line: 1, Column: 0]</font>
<br><font size=2 face="Courier New"> at
org.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.getMethod(<u>ReflectiveAccessorOptimizer.java:906</u>)</font>
<br><font size=2 face="Courier New"> at
org.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.getBeanProperty(<u>ReflectiveAccessorOptimizer.java:585</u>)</font>
<br><font size=2 face="Courier New"> at
org.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.compileGetChain(<u>ReflectiveAccessorOptimizer.java:313</u>)</font>
<br><font size=2 face="Courier New"> at
org.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.optimizeAccessor(<u>ReflectiveAccessorOptimizer.java:138</u>)</font>
<br><font size=2 face="Courier New"> at
org.mvel2.ast.ASTNode.getReducedValueAccelerated(<u>ASTNode.java:133</u>)</font>
<br><font size=2 face="Courier New"> at
org.mvel2.compiler.ExecutableAccessor.getValue(<u>ExecutableAccessor.java:37</u>)</font>
<br><font size=2 face="Courier New"> at
org.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.getCollectionProperty(<u>ReflectiveAccessorOptimizer.java:633</u>)</font>
<br><font size=2 face="Courier New"> at
org.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.compileGetChain(<u>ReflectiveAccessorOptimizer.java:319</u>)</font>
<br><font size=2 face="Courier New"> at
org.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.optimizeAccessor(<u>ReflectiveAccessorOptimizer.java:138</u>)</font>
<br><font size=2 face="Courier New"> at
org.mvel2.ast.ASTNode.getReducedValueAccelerated(<u>ASTNode.java:133</u>)</font>
<br><font size=2 face="Courier New"> at
org.mvel2.ast.BinaryOperation.getReducedValueAccelerated(<u>BinaryOperation.java:102</u>)</font>
<br><font size=2 face="Courier New"> at
org.mvel2.MVELRuntime.execute(<u>MVELRuntime.java:85</u>)</font>
<br><font size=2 face="Courier New"> at
org.mvel2.compiler.CompiledExpression.getValue(<u>CompiledExpression.java:104</u>)</font>
<br><font size=2 face="Courier New"> at
org.mvel2.MVEL.executeExpression(<u>MVEL.java:978</u>)</font>
<br><font size=2 face="Courier New"> at
org.drools.base.mvel.MVELPredicateExpression.evaluate(<u>MVELPredicateExpression.java:75</u>)</font>
<br><font size=2 face="Courier New"> at
org.drools.rule.PredicateConstraint.isAllowedCachedLeft(<u>PredicateConstraint.java:295</u>)</font>
<br><font size=2 face="Courier New"> ...
13 more</font>
<br>
<br><font size=2 face="sans-serif">Is this a bug in MVEL or Drools, or
am I using the map access incorrectly?</font>
<br>
<br><font size=2 face="sans-serif">Thanks,</font>
<br><font size=2 face="sans-serif"><br>
</font><font size=3>Steve Ronderos</font>