<br> Godmar,<br><br> We are getting there. Lets forget, as you suggested, the SingletonMap example. Lets take, for instance:<br><br>class MyMapClass extends TreeMap {<br> //...<br>}<br><br> We can't shadow it by using:<br>
<br>Map shadow = new HashMap( myMapInstance );<br><br> This is because you can write rules against your concrete class:<br><br>rule XYZ<br>when<br> MyMapClass( ... )<br>then<br>end<br> <br> So, shadow proxies must be a subclass of the concrete class that is asserted. In this case, it would be a dynamically generated MyMapClassShadowProxy class. <br>
Now, how can we transfer the state from a MyMapClass instance, whose only information we have is that it implements the Map interface, to a newly instantiated MyMapClassShadowProxy instance?<br><br> If MyMapClass respect this "best practice" of having a constructor receiving a Map parameter to do a shallow copy, great, we use that as I explained in my previous e-mail. But the problem with SingletonMap and eventually other user implemented Map/Collection classes is that they may not have such constructor.<br>
<br> So, what I'm trying to say is, we do allow you to assert Map/Collection instances as facts and to reason over then, but at this point you must be careful with which concrete class you use. Asserting a HashMap is fine, asserting a SingletonMap is not.<br>
<br> I know it is far from ideal at this point, but I don't know how to improve that in current codebase. That is why in the next major release we are trying to get rid of shadow facts.<br><br> Options you have to improve that is, for instance, dynamically generated beans. Even using a custom class that has your maps/collections as attributes is better than asserting your maps/collections directly.<br>
<br> A blog I wrote a long time ago about dynamically generated beans:<br><br><a href="http://blog.athico.com/2006/12/dynamically-generated-class-beans-as.html">http://blog.athico.com/2006/12/dynamically-generated-class-beans-as.html</a><br>
<br> []s<br> Edson<br><br><div><span class="gmail_quote">2008/2/20, Godmar Back <<a href="mailto:godmar@gmail.com">godmar@gmail.com</a>>:</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
On Feb 20, 2008 12:30 PM, Edson Tirelli <<a href="mailto:tirelli@post.com">tirelli@post.com</a>> wrote:<br> ><br> > Godmar,<br> ><br> > Shadow Facts are a necessary evil in current version. Basically what they<br>
> do is keep the working memory consistent in face of attribute changes on the<br> > facts, that may happen both internally and externally to the working memory.<br> > Our implementation to shadow facts is a lazy proxy that caches the<br>
> values until a safe point to synchronize the actual attribute value with the<br> > one seen by the engine.<br> ><br> > So, the question is: given an object:<br> ><br> > (Map) fact<br> ><br> > How can we create an identical copy of it (shadow), if there is no<br>
> "clone" operation?<br> <br> <br>Can you explain why you require the use of "clone()"?<br> <br> Cloning a map is otherwise easy - it's also referred to as a "shallow<br> copy" -- HashMap's HashMap(Map) constructor will do it.<br>
<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/HashMap.html#HashMap(java.util.Map)">http://java.sun.com/j2se/1.4.2/docs/api/java/util/HashMap.html#HashMap(java.util.Map)</a><br> I know you know that, so explain what necessitates the use of clone().<br>
<br><br> > More than that, the shadow must be a subclass of it.<br> <br> <br>java.util.HashMap is a subclass of Map.<br> <br><br> ><br> > Most Collection and Map implementations have a single parameter<br> > constructor that allows us to do:<br>
><br> ><br> > proxy = (ShadowProxy) this.shadowClass.getConstructor( new Class[]{cls}<br> > ).newInstance( new Object[]{fact} );<br> ><br> > But the SingletonMap you were using does not accept that constructor.<br>
> So, one way is to explicit check if the fact is a SingletonMap and handle it<br> > accordingly, but that is a specific class hack... is there any general<br> > solution we can use?<br> ><br> <br> <br>Forget about the SingletonMap. That was just one of the many things I<br>
tried and failed.<br> <br> Fundamentally, I would like Drools to process facts that were obtained<br> from real-world sources, and these facts have properties I do not know<br> in advance. Therefore, I cannot use beans (or using beans would be<br>
highly inconvenient since it will require changes to Java code<br> whenever I'm referring to a new property, something I'd rather avoid.)<br> <br><br> - Godmar<br> <br><br> ><br> > []s<br> > Edson<br>
><br> > 2008/2/20, Godmar Back <<a href="mailto:godmar@gmail.com">godmar@gmail.com</a>>:<br> > > I don't really understand what you mean by "shadow". What is the<br> > > purpose of such shadowing. Mark's email implies that it has to do with<br>
> > concurrency protection; it's not clear what that means.<br> > ><br> > > In my view, whatever purpose you pursue with "shadowing", it does not<br> > > justify treating beans and maps differently.<br>
> ><br> > > Your example of class Person shows that. If a person has two<br> > > attributes, name and age, then this is equivalent to a map with two<br> > > keys 'name' and 'age'.<br>
> ><br> > > Here's the mapping:<br> > ><br> > > p.getName() corresponds to m["name"]<br> > > p.getAge() corresponds to m["age"]<br> > ><br> > > and setName/setAge accordingly.<br>
> ><br> > > Mathematically, a bean is an associative array with a fixed set of<br> > > keys (called "properties") that map to values. For all practical<br> > > purposes, that is the same as a map. There's no reason to treat them<br>
> > differently. Wherever you'd do "getXXX()" with a bean you'd do<br> > > .get("XXX") with a map.<br> > ><br> > > - Godmar<br> > ><br> > > On Feb 20, 2008 11:25 AM, Edson Tirelli <<a href="mailto:tirelli@post.com">tirelli@post.com</a>> wrote:<br>
> > ><br> > > > Ok, let me show one example. Imagine the class Person, with 2<br> > attributes<br> > > > (name and age) and the corresponding getter/setters.<br> > > > What are the data for that fact that must be shadowed? easy answer:<br>
> just<br> > > > shadow all getXXX() methods (getName and getAge).<br> > > ><br> > > > Now, take a Map. What is the data that must be shadowed?<br> > > ><br> > > > So, we do our best to work with facts that don't follow the javabean<br>
> > > spec, but collections and maps are a complicated beast. Again, if you<br> > have<br> > > > suggestions on how to improve the current support we provide for them,<br> > > > please share with us.<br>
> > ><br> > > > []s<br> > > > Edson<br> > > ><br> > > > 2008/2/20, Godmar Back <<a href="mailto:godmar@gmail.com">godmar@gmail.com</a>>:<br> > > ><br> > > > > On Feb 20, 2008 9:23 AM, Edson Tirelli <<a href="mailto:tirelli@post.com">tirelli@post.com</a>> wrote:<br>
> > > > ><br> > > > > > Godmar,<br> > > > > ><br> > > > > > Short answer: collection/maps objects are not javabeans.<br> > > > > ><br> > > > ><br>
> > > > Explain why this is a problem.<br> > > > ><br> > > > > What is it about JavaBeans that your algorithm relies upon? Is it the<br> > > > > fact that the set of properties remains fixed and can be determined at<br>
> > > > (fact) insertion time via reflection?<br> > > > ><br> > > > > Otherwise, I do not see any conceptual difference between a map and a<br> > > > bean.<br> > > > > If that is the difference, then please allow maps with an immutable<br>
> key<br> > > > set.<br> > > > ><br> > > > > - Godmar<br> > > > ><br> > > > ><br> > > > > > Long answer: collection/maps must be shadowed to ensure<br>
> consistency<br> > > > > > during execution, but how can we shadow the data if it is not<br> > exposed in<br> > > > a<br> > > > > > default, spec manner, as in javabeans? The algorithm we have in<br>
> place<br> > > > right<br> > > > > > now is bellow. As you can see, it is a weak algo, but was the best I<br> > > > could<br> > > > > > come up at that time. If you have any suggestions on how to improve<br>
> > > that, I<br> > > > > > appreciate.<br> > > > > ><br> > > > > > public Object getShadow(final Object fact) throws<br> > > > RuntimeDroolsException<br>
> > > > > {<br> > > > > > ShadowProxy proxy = null;<br> > > > > > if ( isShadowEnabled() ) {<br> > > > > > try {<br> > > > > > if ( Collection.class.isAssignableFrom(<br>
> this.shadowClass<br> > > > )<br> > > > > > || Map.class.isAssignableFrom( this.shadowClass ) ) {<br> > > > > > // if it is a collection, try to instantiate<br>
> using<br> > > > > > constructor<br> > > > > > try {<br> > > > > > proxy = (ShadowProxy)<br> > > > > > this.shadowClass.getConstructor( new Class[]{cls} ).newInstance( new<br>
> > > > > Object[]{fact} );<br> > > > > > } catch ( Exception e ) {<br> > > > > > // not possible to instantiate using<br> > constructor<br>
> > > > > }<br> > > > > > }<br> > > > > > if ( proxy == null ) {<br> > > > > > if ( this.instantiator == null ) {<br>
> > > > > this.setInstantiator();<br> > > > > > }<br> > > > > > proxy = (ShadowProxy)<br> > > > this.instantiator.newInstance();<br>
> > > > > }<br> > > > > ><br> > > > > > proxy.setShadowedObject( fact );<br> > > > > > } catch ( final Exception e ) {<br>
> > > > > System.out.println( "shadow: " +proxy.getClass() +<br> > ":" +<br> > > > > > fact.getClass() );<br> > > > > > throw new RuntimeDroolsException( "Error creating<br>
> shadow<br> > > > > > fact for object: " + fact,<br> > > > > > e );<br> > > > > > }<br> > > > > > }<br>
> > > > > return proxy;<br> > > > > ><br> > > > > ><br> > > > > > }<br> > > > > ><br> > > > > > []s<br> > > > > > Edson<br>
> > > > ><br> > > > > > 2008/2/19, Godmar Back <<a href="mailto:godmar@gmail.com">godmar@gmail.com</a>>:<br> > > > > > > As a general comment, the examples for which I find Drools failing<br>
> are<br> > > > > > > not the actual examples for which my application is failing. It's<br> > just<br> > > > > > > the smallest test case I was able to eliminate.<br> > > > > > ><br>
> > > > > > I'm now a bit concerned about your comment that Maps and<br> > Collections<br> > > > > > > aren't well-defined as Facts. I am planning to make extensive use<br> > of<br>
> > > > > > them (that's also why I'd prefer to use the MVEL dialect, because<br> > in<br> > > > > > > Java I cannot do this without creating Bean wrappers.)<br> > > > > > ><br>
> > > > > > Could you elaborate what makes the semantics not "well-defined".<br> > > > > > ><br> > > > > > > I'm specifically concerned with immutable maps (such as the one<br>
> that<br> > > > > > > would have been returned by Collections.singletonMap), and with<br> > > > > > > collections of maps (such as those obtained via a "from"..."<br>
> clause).<br> > > > > > > I need to insert immutable maps as facts; I understand that the<br> > items<br> > > > > > > returned by "from" aren't inserted as facts.<br>
> > > > > ><br> > > > > > > - Godmar<br> > > > > > ><br> > > > > > > On Feb 19, 2008 3:11 PM, Edson Tirelli <<a href="mailto:tirelli@post.com">tirelli@post.com</a>> wrote:<br>
> > > > > > ><br> > > > > > > > Drools tries to create the ShadowProxy. The reason is that it<br> > > > does<br> > > > > > not<br> > > > > > > > know about the implementation... it just knows it is a Map and<br>
> as<br> > > > so, it<br> > > > > > > > must be shadowed. Problem is that SingletonMap is either final<br> > or<br> > > > does<br> > > > > > not<br> > > > > > > > have a default constructor.<br>
> > > > > > > My recommendation, besides opening a JIRA for this, is avoid<br> > > > > > inserting<br> > > > > > > > collections/maps directly as facts. The semantic for such facts<br>
> is<br> > > > not<br> > > > > > > > clearly defined and it may cause undesired behavior.<br> > > > > > > ><br> > > > > > > > []s<br> > > > > > > > Edson<br>
> > > > > > ><br> > > > > > > > 2008/2/19, Godmar Back <<a href="mailto:godmar@gmail.com">godmar@gmail.com</a>>:<br> > > > > > > > ><br> > > > > > > > ><br>
> > > > > > > ><br> > > > > > > > > Hi,<br> > > > > > > > ><br> > > > > > > > > usings Drools 4.0.4 and MVEL 1.4, this simple rule:<br>
> > > > > > > > ---<br> > > > > > > > > package test;<br> > > > > > > > ><br> > > > > > > > > import java.util.Collections;<br>
> > > > > > > ><br> > > > > > > > > dialect "mvel"<br> > > > > > > > ><br> > > > > > > > > rule "Rule #1"<br>
> > > > > > > > when<br> > > > > > > > > then<br> > > > > > > > > insert(Collections.singletonMap("content", "hello"));<br> > > > > > > > > end<br>
> > > > > > > > --<br> > > > > > > > ><br> > > > > > > > > produces:<br> > > > > > > > > java.lang.IllegalAccessError: class<br>
> > > > > > > ><br> > org.drools.shadow.java.util.Collections$SingletonMapShadowProxy<br> > > > cannot<br> > > > > > > > > access its superclass java.util.Collections$SingletonMap<br>
> > > > > > > > at java.lang.ClassLoader.defineClass1(Native Method)<br> > > > > > > > > at<br> > java.lang.ClassLoader.defineClass(ClassLoader.java:620)<br>
> > > > > > > > at<br> > > > > > > ><br> > > > > ><br> > > ><br> > org.drools.rule.MapBackedClassLoader.fastFindClass(MapBackedClassLoader.java:60)<br>
> > > > > > > > at<br> > > > > > > ><br> > > > > ><br> > > ><br> > org.drools.rule.MapBackedClassLoader.loadClass(MapBackedClassLoader.java:79)<br>
> > > > > > > > at<br> > java.lang.ClassLoader.loadClass(ClassLoader.java:251)<br> > > > > > > > > at<br> > > > > > > ><br> > > > > ><br>
> > ><br> > org.drools.reteoo.Rete$ClassObjectTypeConf.loadOrGenerateProxy(Rete.java:547)<br> > > > > > > > > at<br> > > > > > > ><br> > > > > ><br>
> > ><br> > org.drools.reteoo.Rete$ClassObjectTypeConf.defineShadowProxyData(Rete.java:494)<br> > > > > > > > > at<br> > > > > > > > org.drools.reteoo.Rete$ClassObjectTypeConf.<init>(Rete.java:461)<br>
> > > > > > > > at org.drools.reteoo.Rete.assertObject(Rete.java:152)<br> > > > > > > > > at<br> > > > > > > ><br> > > > org.drools.reteoo.ReteooRuleBase.assertObject(ReteooRuleBase.java:192)<br>
> > > > > > > > at<br> > > > > > > ><br> > > > > ><br> > > ><br> > org.drools.reteoo.ReteooWorkingMemory.doInsert(ReteooWorkingMemory.java:71)<br>
> > > > > > > > at<br> > > > > > > ><br> > > > > ><br> > > ><br> > org.drools.common.AbstractWorkingMemory.insert(AbstractWorkingMemory.java:909)<br>
> > > > > > > > at<br> > > > > > > ><br> > > > > ><br> > > ><br> > org.drools.common.AbstractWorkingMemory.insert(AbstractWorkingMemory.java:881)<br>
> > > > > > > > at<br> > > > > > > ><br> > > > > ><br> > > ><br> > org.drools.base.DefaultKnowledgeHelper.insert(DefaultKnowledgeHelper.java:67)<br>
> > > > > > > > at<br> > > > > > > ><br> > > > > ><br> > > ><br> > org.drools.base.DefaultKnowledgeHelper.insert(DefaultKnowledgeHelper.java:61)<br>
> > > > > > > ><br> > > > > > > > ><br> > > > > > > > > It's not clear to me why Drools creates Proxies for such<br> > classes<br> > > > as<br>
> > > > > > > > java.util.Collections, or does MVEL do it?<br> > > > > > > > ><br> > > > > > > > > - Godmar<br> > > > > > > > > _______________________________________________<br>
> > > > > > > > rules-users mailing list<br> > > > > > > > > <a href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a><br> > > > > > > > > <a href="https://lists.jboss.org/mailman/listinfo/rules-users">https://lists.jboss.org/mailman/listinfo/rules-users</a><br>
> > > > > > > ><br> > > > > > > ><br> > > > > > > ><br> > > > > > > ><br> > > > > > > > --<br> > > > > > > > Edson Tirelli<br>
> > > > > > > JBoss Drools Core Development<br> > > > > > > > Office: +55 11 3529-6000<br> > > > > > > > Mobile: +55 11 9287-5646<br> > > > > > > > JBoss, a division of Red Hat @ <a href="http://www.jboss.com">www.jboss.com</a><br>
> > > > > > > _______________________________________________<br> > > > > > > > rules-users mailing list<br> > > > > > > > <a href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a><br>
> > > > > > > <a href="https://lists.jboss.org/mailman/listinfo/rules-users">https://lists.jboss.org/mailman/listinfo/rules-users</a><br> > > > > > > ><br> > > > > > > ><br>
> > > > > > _______________________________________________<br> > > > > > > rules-users mailing list<br> > > > > > > <a href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a><br>
> > > > > > <a href="https://lists.jboss.org/mailman/listinfo/rules-users">https://lists.jboss.org/mailman/listinfo/rules-users</a><br> > > > > > ><br> > > > > ><br> > > > > ><br>
> > > > ><br> > > > > > --<br> > > > > > Edson Tirelli<br> > > > > > JBoss Drools Core Development<br> > > > > > Office: +55 11 3529-6000<br>
> > > > > Mobile: +55 11 9287-5646<br> > > > > > JBoss, a division of Red Hat @ <a href="http://www.jboss.com">www.jboss.com</a><br> > > > > > _______________________________________________<br>
> > > > > rules-users mailing list<br> > > > > > <a href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a><br> > > > > > <a href="https://lists.jboss.org/mailman/listinfo/rules-users">https://lists.jboss.org/mailman/listinfo/rules-users</a><br>
> > > > ><br> > > > > ><br> > > > > _______________________________________________<br> > > > > rules-users mailing list<br> > > > > <a href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a><br>
> > > > <a href="https://lists.jboss.org/mailman/listinfo/rules-users">https://lists.jboss.org/mailman/listinfo/rules-users</a><br> > > > ><br> > > ><br> > > ><br> > > ><br>
> > ><br> > > > --<br> > > > Edson Tirelli<br> > > > JBoss Drools Core Development<br> > > > Office: +55 11 3529-6000<br> > > > Mobile: +55 11 9287-5646<br> > > > JBoss, a division of Red Hat @ <a href="http://www.jboss.com">www.jboss.com</a><br>
> > > _______________________________________________<br> > > > rules-users mailing list<br> > > > <a href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a><br> > > > <a href="https://lists.jboss.org/mailman/listinfo/rules-users">https://lists.jboss.org/mailman/listinfo/rules-users</a><br>
> > ><br> > > ><br> > > _______________________________________________<br> > > rules-users mailing list<br> > > <a href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a><br>
> > <a href="https://lists.jboss.org/mailman/listinfo/rules-users">https://lists.jboss.org/mailman/listinfo/rules-users</a><br> > ><br> ><br> ><br> ><br> > --<br> > Edson Tirelli<br> > JBoss Drools Core Development<br>
> Office: +55 11 3529-6000<br> > Mobile: +55 11 9287-5646<br> > JBoss, a division of Red Hat @ <a href="http://www.jboss.com">www.jboss.com</a><br> > _______________________________________________<br> > rules-users mailing list<br>
> <a href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a><br> > <a href="https://lists.jboss.org/mailman/listinfo/rules-users">https://lists.jboss.org/mailman/listinfo/rules-users</a><br> ><br>
><br> _______________________________________________<br> rules-users mailing list<br> <a href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a><br> <a href="https://lists.jboss.org/mailman/listinfo/rules-users">https://lists.jboss.org/mailman/listinfo/rules-users</a><br>
</blockquote></div><br><br clear="all"><br>-- <br> Edson Tirelli<br> JBoss Drools Core Development<br> Office: +55 11 3529-6000<br> Mobile: +55 11 9287-5646<br> JBoss, a division of Red Hat @ <a href="http://www.jboss.com">www.jboss.com</a>