wolfgang,
I didnt get it, so does that mean that all CE will be re-evaluated on every
change of workingmemory no matter which rule fired? even when executing RHS.
I didnt test it with copy of list yet. I will do it and see.
On Sun, Sep 11, 2011 at 11:28 AM, Wolfgang Laun <wolfgang.laun(a)gmail.com>wrote:
The result of the collect CE is changed due to the modify. You have
to
copy the list and use the copy in the loop.
-W
2011/9/9 Sandeep Bandela <gibsosmat(a)gmail.com>:
> Thanks wolfgang, for the info and that workaround.
> I think there is some off by one error in for loop, or may be some
mistake
> that I didnt notice in my code. the following rule with 3 objects gives
> index out of bound error. I am attaching java & drl file (package
> com.example.drools.testing). I am using 5.2.0 final release.
>
> rule "Buy X units of Product A and Get Y units of Product B Free"
> when
> $itemsA : ArrayList( $a : size >= 2 ) from collect( CartItem(
> productId == "A", processed == false) )
> $itemsB : ArrayList( $b : size >= 1 ) from collect( CartItem(
> productId == "B", processed == false) )
> $m : RuleMessage()
> then
> $m.addMessage("sizes- A="+$a + " B="+$b);
> int $x = 2;
> int $y = 1;
> $m.addMessage("sizes- X="+$x + " Y="+$y);
> for(int i=0 ; i < $x ; i++){
> CartItem $ci = (CartItem) $itemsA.get(i);
> $m.addMessage( $ci.getId()+")Found item:
"+$ci.getProductId());
> modify((CartItem)$ci){
> setProcessed(true),
> setPromoItemDiscount(0D),
> setPromoId("2"),
> setBundleId(bundler.getId()),
> setAggregatorId(1)
> };
> };
> for(int i=0 ; i < $y ; i++){
> CartItem $ci = (CartItem) $itemsB.get(i);
> $m.addMessage( $ci.getId()+")Found item:
"+$ci.getProductId());
> modify((CartItem)$ci){
> setProcessed(true),
> setPromoItemDiscount($ci.getPrice()),
> setPromoId("2"),
> setBundleId(bundler.getId()),
> setAggregatorId(2)
> };
> };
> bundler.increment();
> end
>
>
> error
> Exception in thread "main" org.drools.runtime.rule.ConsequenceException:
> rule: Buy X units of Product A and Get Y units of Product B Free
>
> at
>
org.drools.runtime.rule.impl.DefaultConsequenceExceptionHandler.handleException(DefaultConsequenceExceptionHandler.java:39)
> at
> org.drools.common.DefaultAgenda.fireActivation(DefaultAgenda.java:916)
> at
org.drools.common.DefaultAgenda.fireNextItem(DefaultAgenda.java:845)
> at
org.drools.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:1056)
> at
>
org.drools.common.AbstractWorkingMemory.fireAllRules(AbstractWorkingMemory.java:733)
> at
>
org.drools.common.AbstractWorkingMemory.fireAllRules(AbstractWorkingMemory.java:699)
> at
>
org.drools.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:218)
> at com.example.drools.testing.Main.main(Main.java:52)
> Caused by: java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
> at java.util.ArrayList.RangeCheck(ArrayList.java:547)
> at java.util.ArrayList.get(ArrayList.java:322)
> at
>
com.example.drools.testing.Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.defaultConsequence(Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java:12)
> at
>
com.example.drools.testing.Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0DefaultConsequenceInvoker.evaluate(Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0DefaultConsequenceInvoker.java:44)
> at
> org.drools.common.DefaultAgenda.fireActivation(DefaultAgenda.java:906)
> ... 6 more
>
>
> 2011/9/9 Wolfgang Laun <wolfgang.laun(a)gmail.com>
>>
>> If the declared type of productId and getProductId() is String, it
should
>> be compared to a string literal. (A conversion might be made, but don't
rely
>> on that.)
>>
>> You cannot access components of a global in RHS code using the
simplified
>> notation (not unless you use "mvel" - but don't do that.) Here,
all
accesses
>> should be written the usual Java way, with getter and setter calls.
>>
>> The problem you have with modify(ci) is a bug (fixed for 5.3.0). As a
>> workaround,use
>>
>> modify( (CartItem)ci ){ ... }
>>
>> -W
>>
>>
>> 2011/9/9 Sandeep Bandela <gibsosmat(a)gmail.com>
>>>
>>> some more info for the modify() problem, the CartItem is an interface
and
>>> the implementation is CartItemImpl. if this info leads to some clues.
>>>
>>>
>>> On Fri, Sep 9, 2011 at 1:28 PM, Sandeep Bandela <gibsosmat(a)gmail.com>
>>> wrote:
>>>>
>>>> Hi here is the same thing converted to mvl
>>>>
>>>> // this Bundler.java has integer member that keeps incrementing
>>>> global Bundler bundler
>>>>
>>>> rule "Apply 10% discount if you purchase 2 items"
>>>> when
>>>> $s1 : CartItem( productId == 219759, processed == false)
>>>> $s2 : CartItem( this != $s1, productId == $s1.productId,
>>>> processed == false)
>>>> $m : RuleMessage()
>>>> then
>>>> $m.addMessage("Found item1: " + $s1.getName() + "
id:
>>>> "+$s1.getId());
>>>> $m.addMessage("Found item2: " + $s2.getName() + "
id:
>>>> "+$s2.getId());
>>>> modify($s1){
>>>> setProcessed(true),
>>>> setPromoItemDiscount($s1.getPrice() * 0.1),
>>>> setPromoId("1"),
>>>> setBundleId(bundler.getId()),
>>>> setAggrigatorId(1)
>>>> };
>>>> modify($s2){
>>>> setProcessed(true),
>>>> setPromoItemDiscount($s2.getPrice() * 0.1),
>>>> setPromoId("1"),
>>>> setBundleId(bundler.getId()),
>>>> setAggrigatorId(1)
>>>> };
>>>> $m.addMessage("bundled ["+bundler.getId()+"]
>>>> "+$s1.getId()+","+$s2.getId());
>>>> bundler.increment();
>>>> end
>>>>
>>>> the above rule dosent fire, but if I change the highlighter to
>>>> getProductId() == 219759, or use productId == "219759", may be
this is
some
>>>> edge case but it took long time for me to figure it out productId is
String.
>>>> now consider the bundler.getId(), if I use bundler.id I get
compilation
>>>> error.
>>>>
>>>> Rule Compilation error : [Rule name='Apply 10% discount if you
purchase
>>>> 2 items']
>>>>
>>>>
com/example/promotions/promotionEngine/Rule_Apply_10__discount_if_you_purchase_2_items_0.java
>>>> (23:1592) : The field Bundler.id is not visible
>>>> 2011-09-09 13:18:39,863 INFO [STDOUT] - 2011-09-09 13:18:39,863 INFO
>>>> [PromotionsManager] - ksession initialized
>>>> 2011-09-09 13:18:39,863 INFO [STDOUT] - 2011-09-09 13:18:39,863 INFO
>>>> [PromotionsManager] - Exploding items and inserting cart
>>>> 2011-09-09 13:18:39,864 INFO [STDOUT] - 2011-09-09 13:18:39,863 ERROR
>>>> [CheckOutBasedUtilities] - Failed to apply promo offers
>>>> java.lang.RuntimeException: Unexpected global [bundler]
>>>> at
>>>>
org.drools.common.AbstractWorkingMemory.setGlobal(AbstractWorkingMemory.java:613)
>>>> at
>>>>
org.drools.impl.StatefulKnowledgeSessionImpl.setGlobal(StatefulKnowledgeSessionImpl.java:332)
>>>> at
>>>>
com.example.promotions.promotionEngine.PromotionsManager.applyOffers(PromotionsManager.java:154)
>>>> at
>>>>
com.example.promotions.promotionEngine.PromotionsManager.shuffleForOffers(PromotionsManager.java:61)`
>>>>
>>>> lastly my actual problem that I am looking for a solution lets say we
>>>> have "Buy X items of A and get Y Items of B". X=5 & Y=4
from the
original
>>>> problem I want to template the rule and load the values of X,A,Y,B
from
>>>> database or excel etc. if I use modify the error is as follows
>>>>
>>>> my rule
>>>>
>>>>
>>>> rule "Buy X units of Product A and Get Y units of Product B
Free"
>>>> when
>>>> $itemsX : ArrayList( size == 2 ) from collect( CartItem(
>>>> getProductId() == 24257, !isProcessed()))
>>>> $itemsY : ArrayList( size == 1) from collect(CartItem(
>>>> getProductId() == 24260, !isProcessed()))
>>>> $m : RuleMessage()
>>>> then
>>>> for(Object item : $itemsX){
>>>> CartItem ci = (CartItem) item;
>>>> $m.addMessage( ci.getId()+")Found item:
"+ci.getItemId()+"
>>>> name: "+ci.getName());
>>>> modify(ci){
>>>> setProcessed(true),
>>>> setPromoItemDiscount(0),
>>>> setPromoId("2"),
>>>> setBundleId(bundler.getId()),
>>>> setAggrigatorId(1)
>>>> };
>>>> }
>>>> for(Object item : $itemsY){
>>>> CartItem ci = (CartItem) item;
>>>> $m.addMessage( ci.getId()+")Found item:
"+ci.getItemId()+"
>>>> name: "+ci.getName());
>>>> modify(ci){
>>>> setProcessed(true),
>>>> setPromoItemDiscount(ci.getPrice()),
>>>> setPromoId("2"),
>>>> setBundleId(bundler.getId()),
>>>> setAggrigatorId(2)
>>>> };
>>>> }
>>>> bundler.increment();
>>>> end
>>>>
>>>> Rule Compilation error : [Rule name='Buy X units of Product A and
Get
Y
>>>> units of Product B Free']
>>>>
>>>>
com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>>>> (11:1236) : The method setProcessed(boolean) is undefined for the type
>>>> Object
>>>>
>>>>
com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>>>> (12:1265) : The method setPromoItemDiscount(int) is undefined for the
type
>>>> Object
>>>>
>>>>
com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>>>> (13:1299) : The method setPromoId(String) is undefined for the type
Object
>>>>
>>>>
com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>>>> (14:1325) : The method setBundleId(Integer) is undefined for the type
Object
>>>>
>>>>
com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>>>> (15:1364) : The method setAggrigatorId(int) is undefined for the type
Object
>>>>
>>>>
com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>>>> (22:1702) : The method setProcessed(boolean) is undefined for the type
>>>> Object
>>>>
>>>>
com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>>>> (23:1731) : The method setPromoItemDiscount(Double) is undefined for
the
>>>> type Object
>>>>
>>>>
com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>>>> (24:1777) : The method setPromoId(String) is undefined for the type
Object
>>>>
>>>>
com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>>>> (25:1803) : The method setBundleId(Integer) is undefined for the type
Object
>>>>
>>>>
com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>>>> (26:1842) : The method setAggrigatorId(int) is undefined for the type
Object
>>>>
>>>> Rule Compilation error : [Rule name='Apply 10% discount if you
purchase
>>>> 2 items']
>>>>
>>>>
com/example/promotions/promotionEngine/Rule_Apply_10__discount_if_you_purchase_2_items_0.java
>>>> (23:1592) : The field Bundler.id is not visible
>>>>
>>>>
>>>> On Fri, Sep 9, 2011 at 12:40 PM, Sandeep Bandela
<gibsosmat(a)gmail.com
>
>>>> wrote:
>>>>>
>>>>> Hi Wolfgang,
>>>>> This is what I did initially but for product > 2 I didnt find a
generic
>>>>> way to do this. following is my first rule. I didnt use field names
because
>>>>> it was giving error that member is not accessible. I will attach
the
errors
>>>>> of each case in a few mins.
>>>>>
>>>>> rule "Apply 10% discount if you purchase 2 items"
>>>>> dialect "java"
>>>>> when
>>>>> $s1 : CartItem( getProductId() == 236061, !isProcessed())
>>>>> $s2 : CartItem( getProductId() == 236061, getId() !=
>>>>> $s1.getId(), !isProcessed())
>>>>> $m : RuleMessage()
>>>>> then
>>>>> $m.addMessage("Found item1: " + $s1.getName() +
" id:
>>>>> "+$s1.getId());
>>>>> $m.addMessage("Found item2: " + $s2.getName() +
" id:
>>>>> "+$s2.getId());
>>>>> modify($s1){
>>>>> setProcessed(true),
>>>>> setPromoItemDiscount($s1.getPrice() * 0.1),
>>>>> setPromoId("1"),
>>>>> setBundleId(bundler.getId()),
>>>>> setAggrigatorId(1)
>>>>> };
>>>>> modify($s2){
>>>>> setProcessed(true),
>>>>> setPromoItemDiscount($s2.getPrice() * 0.1),
>>>>> setPromoId("1"),
>>>>> setBundleId(bundler.getId()),
>>>>> setAggrigatorId(1)
>>>>> };
>>>>> bundler.increment();
>>>>> end
>>>>>
>>>>> 2011/9/9 Wolfgang Laun <wolfgang.laun(a)gmail.com>
>>>>>>
>>>>>> Your rule exhibits procedural thinking. (For an aspiring rule
>>>>>> programmer his is typical teething troubles.)
>>>>>>
>>>>>> There's no need to collect all A's and B's in order
to determine
their
>>>>>> number being greater than one or two - this is achieved
automatically by a
>>>>>> simple triple match rule. Consider
>>>>>>
>>>>>> rule "2A - 1B"
>>>>>> when
>>>>>> $a1: CartItem( productId == "A", processed == false
)
>>>>>> $a2: CartItem( this != $a1, productId == "A",
processed == false
)
>>>>>> $b: CartItem( productId == "B", processed == false
)
>>>>>> then
>>>>>> modify( $a1 ){...}
>>>>>> modify( $a2 ){...}
>>>>>> modify( $b ){...}
>>>>>> end
>>>>>>
>>>>>> Note:
>>>>>>
>>>>>> The modify is essential. (When you say "doesn't
work", always
provide
>>>>>> details.)
>>>>>> Use the field name rather than the getter call - it improves
>>>>>> readability.
>>>>>> I'm not sure whether 5.2.0 final handles boolean fields
correctly -
>>>>>> IIRC, there were some issues. It's possible that
CartItem(...,
!processed)
>>>>>> works.
>>>>>>
>>>>>> -W
>>>>>>
>>>>>> 2011/9/8 Sandeep Bandela <gibsosmat(a)gmail.com>
>>>>>>>
>>>>>>> Hi,
>>>>>>> I am new to rules engine, after going through the examples
shipped
>>>>>>> (shopping.drl, petstore.drl)
>>>>>>> I am trying to implement promotional discounting using
drools 5.2.0
>>>>>>> final, stateful session. assume cart has all the items that
customer wants
>>>>>>> to buy,
>>>>>>> I am trying to bundle them together with the existing
offers
>>>>>>>
>>>>>>> rule "Buy X units of Product A and Get Y units of
Product B Free"
>>>>>>> dialect "java"
>>>>>>> when
>>>>>>> $itemsA : ArrayList( size >= 2) from collect(
CartItem(
>>>>>>> getProductId() == "A", !isProcessed()))
>>>>>>> $itemsB : ArrayList( size >= 1) from collect(
CartItem(
>>>>>>> getProductId() == "B", !isProcessed()))
>>>>>>> then
>>>>>>> // current scenario buy 2*A and get 1*B
>>>>>>> int x = 2;
>>>>>>> int y = 1;
>>>>>>> for(int i=0 ; i < x ; i++){
>>>>>>> CartItem $ci = (CartItem) $itemsA.get(i);
>>>>>>> // modify($ci){setProcessed(true) ... } dosent work
>>>>>>> $ci.setProcessed(true);
>>>>>>> $ci.setItemDiscount(0.0);
>>>>>>> $ci.setBundleId(bundler.getId());
>>>>>>> }
>>>>>>>
>>>>>>> for(int i=0 ; i < y ; i++){
>>>>>>> CartItem $ci = (CartItem) $itemsB.get(i);
>>>>>>> $ci.setProcessed(true);
>>>>>>> $ci.setItemDiscount($ci.getPrice());
>>>>>>> $ci.setBundleId(bundler.getId());
>>>>>>> }
>>>>>>> // global counter to identify bundled items
>>>>>>> bundler.increment();
>>>>>>> end
>>>>>>>
>>>>>>> the above rule calculates only for 1 set of offer i.e first
2*A &
1*B
>>>>>>> are considered, rest in the cart are not bundled.
>>>>>>> if customer buys 4*A + 2*B it dosent consider it. am I
missing
>>>>>>> anything? is this the right way to do it?
>>>>>>> any feedback is appreciated.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> Regards,
>>>>>>> Sandeep Bandela.
>>>>>>>
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> rules-users mailing list
>>>>>>> rules-users(a)lists.jboss.org
>>>>>>>
https://lists.jboss.org/mailman/listinfo/rules-users
>>>>>>>
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> rules-users mailing list
>>>>>> rules-users(a)lists.jboss.org
>>>>>>
https://lists.jboss.org/mailman/listinfo/rules-users
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Regards,
>>>>> Sandeep Bandela.
>>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> Regards,
>>>> Sandeep Bandela.
>>>>
>>>
>>>
>>>
>>> --
>>> Regards,
>>> Sandeep Bandela.
>>>
>>>
>>> _______________________________________________
>>> rules-users mailing list
>>> rules-users(a)lists.jboss.org
>>>
https://lists.jboss.org/mailman/listinfo/rules-users
>>>
>>
>>
>> _______________________________________________
>> rules-users mailing list
>> rules-users(a)lists.jboss.org
>>
https://lists.jboss.org/mailman/listinfo/rules-users
>>
>
>
>
> --
> Regards,
> Sandeep Bandela.
>
>
> _______________________________________________
> rules-users mailing list
> rules-users(a)lists.jboss.org
>
https://lists.jboss.org/mailman/listinfo/rules-users
>
>
_______________________________________________
rules-users mailing list
rules-users(a)lists.jboss.org
https://lists.jboss.org/mailman/listinfo/rules-users