Digester wildcard question

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Digester wildcard question

Mykel Alvis
I have a slightly different need than Frank, but I'm posting with the
same subject line. :)

I'm using XML digester rules to parse configurations.  I have a series
of tags that I think should be matched as wildcards but don't seem to
be.

The code to parse my rules is as follows:

                URL u = this.getClass().getResource("/jave-ruleset-digester.xml");
                Digester digester = DigesterLoader.createDigester(u);
                List l = new ArrayList();
                digester.push(l);
                try {
                        digester.parse(file);
                } catch (IOException e) {
                        log.error(e);
                        throw new RulesParseException(e);
                } catch (SAXException e) {
                        log.error(e);
                        throw new RulesParseException(e);
                }


The rules defs:
------------------------------
<digester-rules>
    <pattern value="javerules/rulesets/ruleset">
        <object-create-rule
classname="com.sungard.omnirules.implementation.jave.rules.RuleList"
/>
        <set-next-rule methodname="add" paramtype="java.lang.Object"/>
        <set-properties-rule/>
        <pattern value="rule">
            <object-create-rule classname="RelationalOperatorRule" />
            <set-next-rule methodname="add" paramtype="Rule" />
            <set-properties-rule/>
            <pattern value="condition">    
                <pattern value="leftoperand">
                    <object-create-rule classname="Variable" />
                    <set-next-rule methodname="setLhs"
paramtype="Variable" />
                    <set-properties-rule/>
                </pattern>            
                <pattern value="operator">
                    <object-create-rule classname="RelationalOperator"
/>
                    <set-next-rule methodname="setOperator"
paramtype="RelationalOperator" />
                    <set-properties-rule/>
                </pattern>            
                <pattern value="rightoperand">
                    <object-create-rule classname="Variable" />
                    <set-next-rule methodname="setRhs"
paramtype="Variable" />
                    <set-properties-rule/>
                </pattern>        
            </pattern>
            <pattern value = "true">
                <object-create-rule classname="ConsequenceList" />
                <set-next-rule methodname="setTrueConsequence"
paramtype="Consequence" />
                <set-properties-rule/>
            </pattern>
            <pattern value = "false">
                <object-create-rule classname="ConsequenceList" />
                <set-next-rule methodname="setFalseConsequence"
paramtype="Consequence" />
                <set-properties-rule/>
            </pattern>
            <pattern value="*/message">
                <object-create-rule classname="Message" />
                <set-next-rule methodname="add" paramtype="Consequence" />
                <set-properties-rule/>
            </pattern>

         </pattern>
    </pattern>
</digester-rules>
----------------------

Parsing the following file

<?xml version="1.0" encoding="ISO-8859-1" ?>
<javerules>
    <rulesets>
        <ruleset name="/WYZX">
            <class>RulesImpl</class>
            <rule name="someotherrulename">
                <condition>
                    <!-- ALWAYS TRUE sort of condition -->
                    <leftoperand key="current.someproperty"
description="descofcurrent.someprop" />
                    <operator operator="=" />
                    <rightoperand key="current.someproperty"
description="descofcurrent.someprop" />
                </condition>
                <true>
                    <message message="Always true is true"/>
                    <message message="Always true is STILL true" />
                </true>
                <false>
                    <message message="Always true is false" />
                    <message message="Always true is also false" />
                    <message message="Always true is STILL false" />
                </false>
            </rule>
            <rule name="WEQE">
                <condition>
                    <leftoperand key="current.someproperty"
description="descofcurrent.someprop" />
                    <operator operator="=" />
                    <rightoperand key="previous.someproperty"
description="descofprevious.someprop" />
                </condition>
                <true>
                    <message name="truemessage" message="True fired!"
terminationPoint="true" />
                </true>
                <false>
                        <message name="somemessage" description="desc"
mesage="False fired!" />
                </false>
            </rule>
        </ruleset>
    </rulesets>
</javerules>

-----

Class definitions as follows:

public class ConsequenceList extends BaseConsequence implements
Consequence, Serializable {
...
    public void add(Consequence consequence)
        {
                list.add(consequence);
        }

}
public class Message extends BaseConsequence implements Consequence,
Serializable {
...blah
}


What I'm trying to do is have a single rule for adding Consquence
instances to either the true or false ConsequenceList, depending on if
they're contained inside a <true> tag or a <false> tag
Noting that */message as a pattern should invoke the rule to create a
Message and it's set-next should invoke an add on the next-to-the-top
of the stack, and being that that item is a ConsequnceList which has
an add element to it, I thought this would work.  However, per the
log:
-------------------------
DEBUG (SetPropertiesRule.java:243)
[SetPropertiesRule]{javerules/rulesets/ruleset/rule/true} Set
ConsequenceList properties
DEBUG (BeanUtilsBean.java:795) BeanUtils.populate(ConsequenceList@93df2c[
  ConsequenceList@93df2c[
  list=[]
  parameters=<null>
]
  List=[]
  Termination Point=false
], {})
DEBUG (Digester.java:1002) characters(
                                        )
DEBUG (Digester.java:1318) startElement(,,message)
DEBUG (Digester.java:1325)   Pushing body text '
                                        '
DEBUG (Digester.java:1344)   New
match='javerules/rulesets/ruleset/rule/true/message'
DEBUG (Digester.java:1372)   No rules found matching
'javerules/rulesets/ruleset/rule/true/message'.
DEBUG (Digester.java:1072) endElement(,,message)
DEBUG (Digester.java:1075)  
match='javerules/rulesets/ruleset/rule/true/message'
DEBUG (Digester.java:1076)   bodyText=''
DEBUG (Digester.java:1111)   No rules found matching
'javerules/rulesets/ruleset/rule/true/message'.
DEBUG (Digester.java:1118)   Popping body text '
                                        '
DEBUG (Digester.java:1002) characters(
                                )
DEBUG (Digester.java:1072) endElement(,,true)
--------


No rules found matching 'javerules/rulesets/ruleset/rule/true/message'
is definitely not what I expected to see.
Am I creating my rulesets wrong?  I extended DigesterLoader and set an
ExtendedBaseRules implementation as the rules base in my "create a
digester" code but to no avail.

I would appreciate advice on what I'm doing wrong.

Mykel

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Digester wildcard question

Simon Kitching
On Tue, 2005-06-21 at 10:18 -0500, Mykel Alvis wrote:
> I have a slightly different need than Frank, but I'm posting with the
> same subject line. :)
>
> I'm using XML digester rules to parse configurations.  I have a series
> of tags that I think should be matched as wildcards but don't seem to
> be.

>     <pattern value="javerules/rulesets/ruleset">
...
>         <pattern value="rule">
...
>             <pattern value="*/message">
>                 <object-create-rule classname="Message" />
>                 <set-next-rule methodname="add" paramtype="Consequence" />
>                 <set-properties-rule/>
>             </pattern>

I don't use xmlrules much, but would bet money that this generates a
pattern of "javerules/rulesets/ruleset/rule/*/message". And that sort of
pattern isn't supported by any of the existing rule managers.

The standard RulesBase will support "*/message". The ExtendedBaseRules
will support "message/*". But neither will support a wildcard in the
middle. Well, maybe the RegExRules will, but you don't want to go there
I think.

If you really do want to match "message" elements anywhere in the
document then I suggest moving that <pattern value="*/message"> out to
the top level instead of nesting it within other pattern tags.

>From a brief glance at your rules and examples, though, you might be
better off just duplicating the message stuff under both the true and
false elements.

It looks like an interesting layer you're building on top of digester.
Are you at liberty to discuss what you're trying to achieve?


Regards,

Simon



---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Digester wildcard question

Simon Kitching
On Thu, 2005-06-23 at 22:16 +1200, Simon Kitching wrote:

> It looks like an interesting layer you're building on top of digester.
> Are you at liberty to discuss what you're trying to achieve?

And by the way, have you had a look at the "plugins" module for Digester
(example usage is in src/examples/plugins). It *might* be related to the
kind of stuff you're doing.

Regards,

Simon


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Digester wildcard question

Mykel Alvis
Hey Simon, thanks for getting back to me.

Hrmmm....I was afraid of that. In fact the exact pattern is
"javerules/rulesets/ruleset/rule/*/message" which matches nothing in my
ruleset.
I did move all the pertinent sub-elements to the outer level, which means
I'm going to have break down and actually write a DTD and use xml
validation. I guess this is all the motivation I need to force me to do
things correctly.

Just out of curiosity, is the RegExRules just broken or simple
not-ready-for-prime-time? After the Extended rules didn't work out, I wasn't
too keen on heading down an even more complicated path so I'll admit I
didn't even try...

I have not looked into the plugins. And now, looking for the plugins docs, I
realized I've made a huge mistake. The "Guide" link goes to a page that
appears to be Javadoc generated...and I thought it was JUST javadocs.
Therefore I didn't scroll down to the actual guide...doh! Man, have I been
working in a vacuum. :) Just now I went to a co-worker and he thought
exactly the same thing. We were just under the impression that Digester was
grossly under-documented and secretly cursing all of you under our breath.
Glad to know how wrong I was. Maybe you could move some of the guide links
up above the class references stuff for those of us too dumb to scroll down.

I don't think the plugins are really related to what I'm doing. I could
probably use a plugin to clean up a few classes here and there. However, the
substitution extensions might be terribly useful, since I'm already using
them by using commons-config to hold all my configurations.

This is my first serious foray into Digester and I put the Jakarta Commons
Cookbook and Apache Jakarta Commons: Reusable Java™ Components onto my
Safari bookshelf, used my download tokens to get the chapters on BeanUtils
and Digester, and a toolbar-level link to the wiki page (thanks!) on my
browser. Since I wasn't smart enough to actually read the guide, I sort of
wandered through the desert blindly for a few days.

I believe I can tell you some things about how I'm using Digester without
describing the domain. Or maybe I'll get fired. :)
My current work implements a java-based rules engine that performs some VERY
basic validations. Currently our customer base uses a desktop app to reach
our backend systems. We're making a struts-based alternative to that. The
customer base uses VBA inside the desktop app to do customizations, and
we're porting the ability to use that VBA on the browser through the use of
browser helper objects (yikes!), but that's just gross. One of the two
primary functions they use this code for is to perform
implementation-specific validations (field X must not be greater than field
Y + field Z).

I'm using digester to build up the rulesets inside a singleton ObjectFactory
that produces an instance of the specific runtime validations for a given
context.
Another part of this is an extension to DynaBeans that lets me define
arbitrary code that generically retrieves data and places them into a
DynaBean instance by intercepting the "get" call of the bean. I use Digester
to generate the my extended DynaClass definitions from XML. I then have an
ObjectFactory that produces instances of the DynaClass.
A third part is another Digester call that parses xml definitions of our
domain data and provides an overall view of the domain data for a given
context. I haven't implemented an ObjectFactory for this yet, because of the
fourth element of the effort.
The fourth and final Digester call processes a services definition file that
ties all the contexts together to another (usually identical) context that
is specific to our application (usually a screen name).

An intercept inside our base-level action class will do a jndi lookup for a
service context based on the current form and if one exists, it will use
that to populate the rules engine instance with the working data (as
DynaBeans) and run the rules against them. The result of the rules should be
"errors" so it's another level of struts validation but behind the action
class because we retain the previous copy of the form bean and we'll pass
that to the rules instance as "previous" and the current form bean as
"current" and so you can make a rule that says 'if current.fieldx <>
previous.fieldx then message("You're not allowed to change fieldx")'.

My boss is sort-of allergic to drools for some reason so he wrote the first
cut of this rules thing and I carried it forward from there. Funny thing is,
if we would have used drools this entire process would have been complete
weeks ago. The drools implementation of the rules engine is something like 3
classes and maybe 100 lines of code. This validation engine is some 40-odd
classes and I don't even want to know how much new code I've written. :)

Thanks again for your help and for suggesting the plugins since that helped
me pull my head from a nether orifice and actually read the guide :)

On 6/23/05, Simon Kitching <[hidden email]> wrote:

>
> On Thu, 2005-06-23 at 22:16 +1200, Simon Kitching wrote:
>
> > It looks like an interesting layer you're building on top of digester.
> > Are you at liberty to discuss what you're trying to achieve?
>
> And by the way, have you had a look at the "plugins" module for Digester
> (example usage is in src/examples/plugins). It *might* be related to the
> kind of stuff you're doing.
>
> Regards,
>
> Simon
>
>