Godmar,
We are getting there. Lets forget, as you suggested, the SingletonMap
example. Lets take, for instance:
class MyMapClass extends TreeMap {
//...
}
We can't shadow it by using:
Map shadow = new HashMap( myMapInstance );
This is because you can write rules against your concrete class:
rule XYZ
when
MyMapClass( ... )
then
end
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.
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?
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.
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.
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.
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.
A blog I wrote a long time ago about dynamically generated beans:
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
>
>
_______________________________________________
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 @