PS: I think I know where the confusion lies.
You consider maps just another kind of Java object you attempt to
treat like you would treat other objects - by examining their member
fields and methods, constructors, etc.
I was under the impression that instances of java.util.Maps would be
treated specially by your engine, i.e., as a collection of properties.
I concluded that since in the MVEL dialect you allow the use of the []
operator in a LHS. It seemed the straightforward thing to do, given
the conceptual equivalency of beans and (fixed-keyset) maps.
Maybe I should rephrase my question then. How do I work with facts for
which the set of properties is not known when I compile the Java
portions of the program in which I'm embedding my Drools rules?
- Godmar
On Wed, Feb 20, 2008 at 12:53 PM, Godmar Back <godmar(a)gmail.com> wrote:
On Feb 20, 2008 12:30 PM, Edson Tirelli <tirelli(a)post.com>
wrote:
>
> Godmar,
>
> Shadow Facts are a necessary evil in current version. Basically what they
> do is keep the working memory consistent in face of attribute changes on the
> facts, that may happen both internally and externally to the working memory.
> Our implementation to shadow facts is a lazy proxy that caches the
> values until a safe point to synchronize the actual attribute value with the
> one seen by the engine.
>
> So, the question is: given an object:
>
> (Map) fact
>
> How can we create an identical copy of it (shadow), if there is no
> "clone" operation?
Can you explain why you require the use of "clone()"?
Cloning a map is otherwise easy - it's also referred to as a "shallow
copy" -- HashMap's HashMap(Map) constructor will do it.
http://java.sun.com/j2se/1.4.2/docs/api/java/util/HashMap.html#HashMap(ja...
I know you know that, so explain what necessitates the use of clone().
> More than that, the shadow must be a subclass of it.
java.util.HashMap is a subclass of Map.
>
> Most Collection and Map implementations have a single parameter
> constructor that allows us to do:
>
>
> proxy = (ShadowProxy) this.shadowClass.getConstructor( new Class[]{cls}
> ).newInstance( new Object[]{fact} );
>
> But the SingletonMap you were using does not accept that constructor.
> So, one way is to explicit check if the fact is a SingletonMap and handle it
> accordingly, but that is a specific class hack... is there any general
> solution we can use?
>
Forget about the SingletonMap. That was just one of the many things I
tried and failed.
Fundamentally, I would like Drools to process facts that were obtained
from real-world sources, and these facts have properties I do not know
in advance. Therefore, I cannot use beans (or using beans would be
highly inconvenient since it will require changes to Java code
whenever I'm referring to a new property, something I'd rather avoid.)
- Godmar
>
> []s
> Edson
>
> 2008/2/20, Godmar Back <godmar(a)gmail.com>:
> > 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(a)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(a)gmail.com>:
> > >
> > > > On Feb 20, 2008 9:23 AM, Edson Tirelli <tirelli(a)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(a)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(a)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(a)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(a)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(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
> > > > > >
> > > > >
> > > > >
> > > > >
> > > > > --
> > > > > 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(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
> > > >
> > >
> > >
> > >
> > >
> > > --
> > > 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(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
> >
>
>
>
> --
> 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(a)lists.jboss.org
>
https://lists.jboss.org/mailman/listinfo/rules-users
>
>