[rules-users] IllegalAccessError in shadow classes

Mark Proctor mproctor at codehaus.org
Wed Feb 20 18:43:20 EST 2008


Drools 4.x assert/retracts, like Jess, are symmetrical. When you assert 
the data it uses the constraints to determine the cross product joins 
which controls the propagation throughout the network. When you do a 
retract it uses those same constraints todetermine the cross product 
joins to be able to propagate through the graph removing itself from the 
node memories where the assert propagation reached before.

Now if we go back to standard Java when you have a HashMap with a 
key/value pair, if you put an object into the map and changed a field on 
the key that changes the hashcode/equals methods you will never be able 
to retrieve the object. It is the same for us, the working memory has 
lots and lots of hash maps.

Now what happens when you modify a bean? a modify is actually a 
retract+assert so when you call update(...) after the field has changed 
how can the retract correct determine all the nodes where the object is 
remembered? It can't as the information is no longer there to determine 
this. To get around this we have to shadow a bean, i.e. make a copy of 
all the bean's fields on insertion. When you call update() the engine 
still sees the old field values, even though they might have been 
updated on the source object. This allows the retract to always behave 
symmetrically to the assert.

With Maps and thus nested objects shadowing becomes very hard. As we 
would have to shadow the entire map and then shadow evey object in that 
map. Which is far from ideal. This is also why with 4.0 you must be 
extremely careful with nested objects, which we recommend are immutable 
while the parent object lives in the network, shadowing an entire object 
graph is simply not practical.

In Drools 3.0 we did not need to shadow as we hade a more complicated 
algorithm that maintained more references allowing for asymetrical 
behaviour - however I couldn't get the algorithm to perform with Jess 
like performance and it used a lot more memory. I dropped Drools 4.0 
back to how Jess does it with shadow facts and symmetrical 
assert/retract. For Drools 5.0 I have re-written the algorithm and have 
managed to get asymettrical behaviour with actual performance increases, 
not losses. This is now in a branch and I hope to merge into trunk soon.

After this the only reason someone would want shadow proxies is to 
protect an object that is currently in the working memory from field 
modifications leaving the network integrity invalid. i.e. if another 
thread changes the field on an object in the working memory and the wm 
is not correctly notified we have an object cached in a state that it no 
longer represents, this will make all join attempts invalid until the 
engine is notified and the object is re-propagated throughout the 
network. As 5.0 will no longer require shadow proxies by default we will 
propably remove the asm proxy implementation we have and instead just 
have an interface and leave the implementation of this to the user, 
probably using aop. This will simplify our engine, and help performance 
a little, so that we offload the solution to problem to those that need it.

Mark

Godmar Back wrote:
> I don't really understand what you mean by "shadow".  What is the
> purpose of such shadowing. Mark's email implies that it has to do with
> concurrency protection; it's not clear what that means.
>
> In my view, whatever purpose you pursue with "shadowing", it does not
> justify treating beans and maps differently.
>
> Your example of class Person shows that. If a person has two
> attributes, name and age, then this is equivalent to a map with two
> keys 'name' and 'age'.
>
> Here's the mapping:
>
> p.getName()    corresponds to m["name"]
> p.getAge() corresponds to m["age"]
>
> and setName/setAge accordingly.
>
> Mathematically, a bean is an associative array with a fixed set of
> keys (called "properties") that map to values. For all practical
> purposes, that is the same as a map. There's no reason to treat them
> differently. Wherever you'd do "getXXX()" with a bean you'd do
> .get("XXX") with a map.
>
>  - Godmar
>
> On Feb 20, 2008 11:25 AM, Edson Tirelli <tirelli at post.com> wrote:
>   
>>    Ok, let me show one example. Imagine the class Person, with 2 attributes
>> (name and age) and the corresponding getter/setters.
>>    What are the data for that fact that must be shadowed? easy answer: just
>> shadow all getXXX() methods (getName and getAge).
>>
>>    Now, take a Map. What is the data that must be shadowed?
>>
>>    So, we do our best to work with facts that don't follow the javabean
>> spec, but collections and maps are a complicated beast. Again, if you have
>> suggestions on how to improve the current support we provide for them,
>> please share with us.
>>
>>    []s
>>    Edson
>>
>> 2008/2/20, Godmar Back <godmar at gmail.com>:
>>
>>     
>>> On Feb 20, 2008 9:23 AM, Edson Tirelli <tirelli at post.com> wrote:
>>>       
>>>>    Godmar,
>>>>
>>>>    Short answer: collection/maps objects are not javabeans.
>>>>
>>>>         
>>> Explain why this is a problem.
>>>
>>> What is it about JavaBeans that your algorithm relies upon?  Is it the
>>> fact that the set of properties remains fixed and can be determined at
>>> (fact) insertion time via reflection?
>>>
>>> Otherwise, I do not see any conceptual difference between a map and a
>>>       
>> bean.
>>     
>>> If that is the difference, then please allow maps with an immutable key
>>>       
>> set.
>>     
>>> - Godmar
>>>
>>>
>>>       
>>>>    Long answer: collection/maps must be shadowed to ensure consistency
>>>> during execution, but how can we shadow the data if it is not exposed in
>>>>         
>> a
>>     
>>>> default, spec manner, as in javabeans? The algorithm we have in place
>>>>         
>> right
>>     
>>>> now is bellow. As you can see, it is a weak algo, but was the best I
>>>>         
>> could
>>     
>>>> come up at that time. If you have any suggestions on how to improve
>>>>         
>> that, I
>>     
>>>> appreciate.
>>>>
>>>>     public Object getShadow(final Object fact) throws
>>>>         
>> RuntimeDroolsException
>>     
>>>> {
>>>>         ShadowProxy proxy = null;
>>>>         if ( isShadowEnabled() ) {
>>>>             try {
>>>>                 if ( Collection.class.isAssignableFrom( this.shadowClass
>>>>         
>> )
>>     
>>>> || Map.class.isAssignableFrom( this.shadowClass ) ) {
>>>>                      // if it is a collection, try to instantiate using
>>>> constructor
>>>>                     try {
>>>>                         proxy = (ShadowProxy)
>>>> this.shadowClass.getConstructor( new Class[]{cls} ).newInstance( new
>>>> Object[]{fact} );
>>>>                      } catch ( Exception e ) {
>>>>                         // not possible to instantiate using constructor
>>>>                     }
>>>>                 }
>>>>                 if ( proxy == null ) {
>>>>                     if ( this.instantiator == null ) {
>>>>                          this.setInstantiator();
>>>>                     }
>>>>                     proxy = (ShadowProxy)
>>>>         
>> this.instantiator.newInstance();
>>     
>>>>                 }
>>>>
>>>>                 proxy.setShadowedObject( fact );
>>>>              } catch ( final Exception e ) {
>>>>                 System.out.println( "shadow: " +proxy.getClass() + ":" +
>>>> fact.getClass() );
>>>>                 throw new RuntimeDroolsException( "Error creating shadow
>>>> fact for object: " + fact,
>>>>                                                    e );
>>>>             }
>>>>         }
>>>>         return proxy;
>>>>
>>>>
>>>>     }
>>>>
>>>>      []s
>>>>      Edson
>>>>
>>>> 2008/2/19, Godmar Back <godmar at gmail.com>:
>>>>         
>>>>> As a general comment, the examples for which I find Drools failing are
>>>>> not the actual examples for which my application is failing. It's just
>>>>> the smallest test case I was able to eliminate.
>>>>>
>>>>> I'm now a bit concerned about your comment that Maps and Collections
>>>>> aren't well-defined as Facts. I am planning to make extensive use of
>>>>> them (that's also why I'd prefer to use the MVEL dialect, because in
>>>>> Java I cannot do this without creating Bean wrappers.)
>>>>>
>>>>> Could you elaborate what makes the semantics not "well-defined".
>>>>>
>>>>> I'm specifically concerned with immutable maps (such as the one that
>>>>> would have been returned by Collections.singletonMap), and with
>>>>> collections of maps (such as those obtained via a "from"..." clause).
>>>>> I need to insert immutable maps as facts; I understand that the items
>>>>> returned by "from" aren't inserted as facts.
>>>>>
>>>>> - Godmar
>>>>>
>>>>> On Feb 19, 2008 3:11 PM, Edson Tirelli <tirelli at post.com> wrote:
>>>>>           
>>>>>>    Drools tries to create the ShadowProxy. The reason is that it
>>>>>>             
>> does
>>     
>>>> not
>>>>         
>>>>>> know about the implementation... it just knows it is a Map and as
>>>>>>             
>> so, it
>>     
>>>>>> must be shadowed. Problem is that SingletonMap is either  final or
>>>>>>             
>> does
>>     
>>>> not
>>>>         
>>>>>> have a default constructor.
>>>>>>     My recommendation, besides opening a JIRA for this, is avoid
>>>>>>             
>>>> inserting
>>>>         
>>>>>> collections/maps directly as facts. The semantic for such facts is
>>>>>>             
>> not
>>     
>>>>>> clearly defined and it may cause undesired behavior.
>>>>>>
>>>>>>    []s
>>>>>>    Edson
>>>>>>
>>>>>> 2008/2/19, Godmar Back <godmar at gmail.com>:
>>>>>>             
>>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>> usings Drools 4.0.4 and MVEL 1.4, this simple rule:
>>>>>>> ---
>>>>>>> package test;
>>>>>>>
>>>>>>> import java.util.Collections;
>>>>>>>
>>>>>>> dialect "mvel"
>>>>>>>
>>>>>>> rule "Rule #1"
>>>>>>> when
>>>>>>> then
>>>>>>>     insert(Collections.singletonMap("content", "hello"));
>>>>>>> end
>>>>>>> --
>>>>>>>
>>>>>>> produces:
>>>>>>> java.lang.IllegalAccessError: class
>>>>>>> org.drools.shadow.java.util.Collections$SingletonMapShadowProxy
>>>>>>>               
>> cannot
>>     
>>>>>>> access its superclass java.util.Collections$SingletonMap
>>>>>>>         at java.lang.ClassLoader.defineClass1(Native Method)
>>>>>>>         at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
>>>>>>>         at
>>>>>>>               
>> org.drools.rule.MapBackedClassLoader.fastFindClass(MapBackedClassLoader.java:60)
>>     
>>>>>>>         at
>>>>>>>               
>> org.drools.rule.MapBackedClassLoader.loadClass(MapBackedClassLoader.java:79)
>>     
>>>>>>>         at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
>>>>>>>         at
>>>>>>>               
>> org.drools.reteoo.Rete$ClassObjectTypeConf.loadOrGenerateProxy(Rete.java:547)
>>     
>>>>>>>         at
>>>>>>>               
>> org.drools.reteoo.Rete$ClassObjectTypeConf.defineShadowProxyData(Rete.java:494)
>>     
>>>>>>>         at
>>>>>>>               
>>>>>> org.drools.reteoo.Rete$ClassObjectTypeConf.<init>(Rete.java:461)
>>>>>>             
>>>>>>>         at org.drools.reteoo.Rete.assertObject(Rete.java:152)
>>>>>>>         at
>>>>>>>               
>> org.drools.reteoo.ReteooRuleBase.assertObject(ReteooRuleBase.java:192)
>>     
>>>>>>>         at
>>>>>>>               
>> org.drools.reteoo.ReteooWorkingMemory.doInsert(ReteooWorkingMemory.java:71)
>>     
>>>>>>>         at
>>>>>>>               
>> org.drools.common.AbstractWorkingMemory.insert(AbstractWorkingMemory.java:909)
>>     
>>>>>>>         at
>>>>>>>               
>> org.drools.common.AbstractWorkingMemory.insert(AbstractWorkingMemory.java:881)
>>     
>>>>>>>         at
>>>>>>>               
>> org.drools.base.DefaultKnowledgeHelper.insert(DefaultKnowledgeHelper.java:67)
>>     
>>>>>>>         at
>>>>>>>               
>> org.drools.base.DefaultKnowledgeHelper.insert(DefaultKnowledgeHelper.java:61)
>>     
>>>>>>> It's not clear to me why Drools creates Proxies for such classes
>>>>>>>               
>> as
>>     
>>>>>>> java.util.Collections, or does MVEL do it?
>>>>>>>
>>>>>>> - Godmar
>>>>>>> _______________________________________________
>>>>>>> rules-users mailing list
>>>>>>> rules-users at lists.jboss.org
>>>>>>> https://lists.jboss.org/mailman/listinfo/rules-users
>>>>>>>
>>>>>>>               
>>>>>>
>>>>>> --
>>>>>>   Edson Tirelli
>>>>>>   JBoss Drools Core Development
>>>>>>    Office: +55 11 3529-6000
>>>>>>   Mobile: +55 11 9287-5646
>>>>>>   JBoss, a division of Red Hat @ www.jboss.com
>>>>>> _______________________________________________
>>>>>> rules-users mailing list
>>>>>> rules-users at lists.jboss.org
>>>>>> https://lists.jboss.org/mailman/listinfo/rules-users
>>>>>>
>>>>>>
>>>>>>             
>>>>> _______________________________________________
>>>>> rules-users mailing list
>>>>> rules-users at lists.jboss.org
>>>>> https://lists.jboss.org/mailman/listinfo/rules-users
>>>>>
>>>>>           
>>>>
>>>> --
>>>>   Edson Tirelli
>>>>   JBoss Drools Core Development
>>>>   Office: +55 11 3529-6000
>>>>   Mobile: +55 11 9287-5646
>>>>   JBoss, a division of Red Hat @ www.jboss.com
>>>> _______________________________________________
>>>> rules-users mailing list
>>>> rules-users at lists.jboss.org
>>>> https://lists.jboss.org/mailman/listinfo/rules-users
>>>>
>>>>
>>>>         
>>> _______________________________________________
>>> rules-users mailing list
>>> rules-users at lists.jboss.org
>>> https://lists.jboss.org/mailman/listinfo/rules-users
>>>
>>>       
>>
>>
>> --
>>   Edson Tirelli
>>   JBoss Drools Core Development
>>   Office: +55 11 3529-6000
>>   Mobile: +55 11 9287-5646
>>   JBoss, a division of Red Hat @ www.jboss.com
>> _______________________________________________
>> rules-users mailing list
>> rules-users at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/rules-users
>>
>>
>>     
> _______________________________________________
> rules-users mailing list
> rules-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-users
>
>   

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-users/attachments/20080220/a4bf374b/attachment.html 


More information about the rules-users mailing list