[Digester] Method call order.

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

[Digester] Method call order.

Eugene.Ng
Greetings,

Decoder Rule XML:
...
<pattern value="Party">
  <object-create-rule
classname="au.com.bankwest.ols.lixi.model.party.LIXIPartyLoader"/>
  <call-method-rule methodname="setApplicationType" paramcount="1"
paramtypes="au.com.bankwest.ols.reference.legalentity.LixiAssociation" />
  <call-param-rule attrname="ApplicationType" paramnumber="0" />
  <set-next-rule methodname="addParty" />
</pattern>
...

Apparently the decoder always calls 'addParty' method BEFORE calling
'setApplicationType' resulting in an incomplete object being added. I've
even tried moving <set-next-rule> to the top (based on the recommendations
of this FAQ 'http://wiki.apache.org/jakarta-commons/Digester/FAQ' under
'How do I get CallMethodRule to fire before SetNextRule?') and it still
gets called first. Anyone with experience on this please share your wisdom.

Thanks!
Eugene.




_______________________________________________________________________________
Unencrypted electronic mail is not secure and may not be authentic.
If you have any doubts as to the contents please telephone to confirm.

This electronic transmission including any attachments is intended only
for those to whom it is addressed. It may contain copyright material or
information that is confidential, privileged or exempt from disclosure by law.
Any claim to privilege is not waived or lost by reason of mistaken transmission
of this information. If you are not the intended recipient you must not
distribute or copy this transmission and should please notify the sender.
Your costs for doing this will be reimbursed by the sender.

We do not accept liability in connection with computer virus, data corruption,
delay, interruption, unauthorised access or unauthorised amendment.
_______________________________________________________________________________


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

Reply | Threaded
Open this post in threaded view
|

Re: [Digester] Method call order.

Simon Kitching
On Fri, 2005-06-03 at 10:38 +0800, [hidden email] wrote:

> Greetings,
>
> Decoder Rule XML:
> ...
> <pattern value="Party">
>   <object-create-rule
> classname="au.com.bankwest.ols.lixi.model.party.LIXIPartyLoader"/>
>   <call-method-rule methodname="setApplicationType" paramcount="1"
> paramtypes="au.com.bankwest.ols.reference.legalentity.LixiAssociation" />
>   <call-param-rule attrname="ApplicationType" paramnumber="0" />
>   <set-next-rule methodname="addParty" />
> </pattern>
> ...
>
> Apparently the decoder always calls 'addParty' method BEFORE calling
> 'setApplicationType' resulting in an incomplete object being added. I've
> even tried moving <set-next-rule> to the top (based on the recommendations
> of this FAQ 'http://wiki.apache.org/jakarta-commons/Digester/FAQ' under
> 'How do I get CallMethodRule to fire before SetNextRule?') and it still
> gets called first. Anyone with experience on this please share your wisdom.

Moving the set-next-rule to before the call-method-rule *will* fix this
problem. I can't think of any reason why it wouldn't work for you.

But if you still have problems, I recommend enabling digester's logging
as described in the same FAQ and inspecting the output.

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] Method call order.

Eugene.Ng
In reply to this post by Eugene.Ng

My mistake. You are right that <set-next-rule> *fixed* it, I mistakenly
mixed it up with another situation. This situation is far more complicated
and I hope I can explain it clearly here...

The XML I'm trying to parse:
<Common>
      <attributes1 attr="common_attributes1"/>
      <attributes2 attr2="common_attributes2"/>
      <Type1>
            <attributes attr="subclass1_attributes"/>
      </Type1>
      <Type2>
            <attributes attr="subclass2_attributes"/>
      </Type2>
</Common>

In this scenario, I'm trying to generate an appropriate object depending on
whether the tag <Type1> or <Type2> appears but both must have common
attributes "common_attributes1" & "common_attributes2" set into them. Since
this is my first time using Digester, I'm unaware of a way to write a
factory at <Common> to peek deeper to get the appropriate Type class to
load. So I introduced a "CommonLoader" intermediate class and wrote the
rules as follows...

<digester-rules>
      <pattern value="Common">
            <object-create-rule classname="CommonLoader"/>
            <call-method-rule methodname="setCommonAttributes1"
paramcount="1" paramtypes="java.lang.Boolean"/>
            <call-param-rule pattern="attributes1" attrname="attr1"
paramnumber="0"/>
            <call-method-rule methodname="setCommonAttributes2"
paramcount="1" />
            <call-param-rule pattern="attributes2" attrname="attr2"
paramnumber="0"/>
            <pattern value="Type1">
                  <object-create-rule classname="Type1"/>
                  <set-next-rule methodname="setType1"/>
                  <call-method-rule methodname="setType1Attribute"
paramcount="1" paramtypes="java.lang.Boolean"/>
                  <call-param-rule pattern="attributes" attrname="attr"
paramnumber="0"/>
            </pattern>
            <pattern value="Type2">
                  <object-create-rule classname="Type2"/>
                  <set-next-rule methodname="setType2"/>
                  <call-method-rule methodname="setType1Attribute"
paramcount="1" paramtypes="java.lang.Boolean"/>
                  <call-param-rule pattern="attributes" attrname="attr"
paramnumber="0"/>
            </pattern>
      </pattern>
</digester-rules>

CommonLoader will have the method setType1() and setType2() and these
methods accepts the object created (either Type1 or Type2) and then sets
the common attributes obtained from within the <Common> tag to these Type
objects. I require that the method setType1() and setType2() be called last
to ensure all the common attributes are loaded into CommonLoader before it
proceeds to set them into the appropriate Type object. However the order of
execution I got is as follows:

1.    setCommonAttributes2.
2.    setType1.
3.    setCommonAttributes1.

Because setType1 as seen above is called before setCommonAttributes1,
common_attribute1 never gets set into the object Type1.

I've got a few workarounds in mind that would work, but before I proceed, I
need to understand as to why setCommonAttributes2() gets called based on
the proper order while setCommonAttributes1() gets called last? Why is the
order not as follows?

1.    setType1
2.    setCommonAttributes2
3.    setCommonAttributes1

However if I were to remove "paramtypes=java.lang.Boolean" and pass it in
as a String then the order will be as follows:

1.    setCommonAttributes1
2.    setCommonAttributes2
3.    setType1

I hope my explanation is clear and the experts out there is able to help.

Cheers,
Eugene

P.S : I've got no control over the XML I'm receiving to modify the source
XML file is out of the question unfortunately.



                                                                                                                               
                      Simon Kitching                                                                                          
                      <skitching@apach         To:      Jakarta Commons Users List <[hidden email]>          
                      e.org>                   cc:                                                                            
                                               Subject: Re: [Digester] Method call order.                                      
                                                                                                                               
                                                                                                                               
                      03/06/2005 11:46                                                                                        
                      AM                                                                                                      
                      Please respond                                                                                          
                      to "Jakarta                                                                                              
                      Commons Users                                                                                            
                      List"                                                                                                    
                                                                                                                               
                                                                                                                               




On Fri, 2005-06-03 at 10:38 +0800, [hidden email] wrote:

> Greetings,
>
> Decoder Rule XML:
> ...
> <pattern value="Party">
>   <object-create-rule
> classname="au.com.bankwest.ols.lixi.model.party.LIXIPartyLoader"/>
>   <call-method-rule methodname="setApplicationType" paramcount="1"
> paramtypes="au.com.bankwest.ols.reference.legalentity.LixiAssociation" />
>   <call-param-rule attrname="ApplicationType" paramnumber="0" />
>   <set-next-rule methodname="addParty" />
> </pattern>
> ...
>
> Apparently the decoder always calls 'addParty' method BEFORE calling
> 'setApplicationType' resulting in an incomplete object being added. I've
> even tried moving <set-next-rule> to the top (based on the
recommendations
> of this FAQ 'http://wiki.apache.org/jakarta-commons/Digester/FAQ' under
> 'How do I get CallMethodRule to fire before SetNextRule?') and it still
> gets called first. Anyone with experience on this please share your
wisdom.

Moving the set-next-rule to before the call-method-rule *will* fix this
problem. I can't think of any reason why it wouldn't work for you.

But if you still have problems, I recommend enabling digester's logging
as described in the same FAQ and inspecting the output.

Regards,

Simon



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







_______________________________________________________________________________
Unencrypted electronic mail is not secure and may not be authentic.
If you have any doubts as to the contents please telephone to confirm.

This electronic transmission including any attachments is intended only
for those to whom it is addressed. It may contain copyright material or
information that is confidential, privileged or exempt from disclosure by law.
Any claim to privilege is not waived or lost by reason of mistaken transmission
of this information. If you are not the intended recipient you must not
distribute or copy this transmission and should please notify the sender.
Your costs for doing this will be reimbursed by the sender.

We do not accept liability in connection with computer virus, data corruption,
delay, interruption, unauthorised access or unauthorised amendment.
_______________________________________________________________________________


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

Reply | Threaded
Open this post in threaded view
|

Re: [Digester] Method call order.

Simon Kitching
On Fri, 2005-06-03 at 13:17 +0800, [hidden email] wrote:

> The XML I'm trying to parse:
> <Common>
>       <attributes1 attr="common_attributes1"/>
>       <attributes2 attr2="common_attributes2"/>
>       <Type1>
>             <attributes attr="subclass1_attributes"/>
>       </Type1>
>       <Type2>
>             <attributes attr="subclass2_attributes"/>
>       </Type2>
> </Common>
>
> In this scenario, I'm trying to generate an appropriate object depending on
> whether the tag <Type1> or <Type2> appears but both must have common
> attributes "common_attributes1" & "common_attributes2" set into them. Since
> this is my first time using Digester, I'm unaware of a way to write a
> factory at <Common> to peek deeper to get the appropriate Type class to
> load.

You can't write a factory to do that. The object must be created when
the start tag is encountered, in order for it to be available to store
attribute info on when that is found. But digester is based on SAX, so
has *no* ability to "look ahead" in the stream of data.

Some variant of your CommonLoader is the way to go I expect - though as
you have found out it isn't easy...

> So I introduced a "CommonLoader" intermediate class and wrote the
> rules as follows...
>
> <digester-rules>
>       <pattern value="Common">
>             <object-create-rule classname="CommonLoader"/>
>             <call-method-rule methodname="setCommonAttributes1"
> paramcount="1" paramtypes="java.lang.Boolean"/>
>             <call-param-rule pattern="attributes1" attrname="attr1"
> paramnumber="0"/>
>             <call-method-rule methodname="setCommonAttributes2"
> paramcount="1" />
>             <call-param-rule pattern="attributes2" attrname="attr2"
> paramnumber="0"/>
>             <pattern value="Type1">
>                   <object-create-rule classname="Type1"/>
>                   <set-next-rule methodname="setType1"/>
>                   <call-method-rule methodname="setType1Attribute"
> paramcount="1" paramtypes="java.lang.Boolean"/>
>                   <call-param-rule pattern="attributes" attrname="attr"
> paramnumber="0"/>
>             </pattern>
>             <pattern value="Type2">
>                   <object-create-rule classname="Type2"/>
>                   <set-next-rule methodname="setType2"/>
>                   <call-method-rule methodname="setType1Attribute"
> paramcount="1" paramtypes="java.lang.Boolean"/>
>                   <call-param-rule pattern="attributes" attrname="attr"
> paramnumber="0"/>
>             </pattern>
>       </pattern>
> </digester-rules>
>
> CommonLoader will have the method setType1() and setType2() and these
> methods accepts the object created (either Type1 or Type2) and then sets
> the common attributes obtained from within the <Common> tag to these Type
> objects. I require that the method setType1() and setType2() be called last
> to ensure all the common attributes are loaded into CommonLoader before it
> proceeds to set them into the appropriate Type object. However the order of
> execution I got is as follows:
>
> 1.    setCommonAttributes2.
> 2.    setType1.
> 3.    setCommonAttributes1.
>
> Because setType1 as seen above is called before setCommonAttributes1,
> common_attribute1 never gets set into the object Type1.
>
> I've got a few workarounds in mind that would work, but before I proceed, I
> need to understand as to why setCommonAttributes2() gets called based on
> the proper order while setCommonAttributes1() gets called last? Why is the
> order not as follows?
>
> 1.    setType1
> 2.    setCommonAttributes2
> 3.    setCommonAttributes1
>
> However if I were to remove "paramtypes=java.lang.Boolean" and pass it in
> as a String then the order will be as follows:
>
> 1.    setCommonAttributes1
> 2.    setCommonAttributes2
> 3.    setType1
>
> I hope my explanation is clear and the experts out there is able to help.

Adding multiple CallMethodRule rules with the same pattern is a bad
idea. It's a design flaw in Digester, and can result in some very
unexpected behaviour. The fundamental cause is that there is just one
"parameter stack" in digester, and CallParamRule objects always operate
on the "parameter-info" structure on the top of the stack.

In your case it's not necessary to have CallMethodRule rules with the
same pattern. I suggest adding the CallMethodRule rules with the same
pattern that triggers their sole parameter:

<pattern value="Common">
  <object-create-rule ...>

  <pattern value="attributes1">
    <call-method-rule name="setCommonAttributes1" paramcount="1" .../>
    <call-param-rule attrname="attr" paramnumber="0"/>
  </pattern>

  <pattern value="attributes2">
    <call-method-rule name="setCommonAttributes2" paramcount="1" .../>
    <call-param-rule attrname="attr" paramnumber="0"/>
  </pattern>

  <pattern value="Type1">
     ....
  </pattern>
</pattern>

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] Method call order.

Eugene.Ng
In reply to this post by Eugene.Ng

Hi Simon,

      I might have missed your point, but how does this explain the
different call order for those with "paramtypes" declared versus those
without "paramtypes"? I'm guessing here that if paramtypes are not
declared, it gets triggered immediately (WITHOUT being pushed into the
stack) ..but when paramtypes are declared it gets pushed into the stack
thus LIFO ???

-
Eugene.



                                                                                                                               
                      Simon Kitching                                                                                          
                      <skitching@apach         To:      Jakarta Commons Users List <[hidden email]>          
                      e.org>                   cc:                                                                            
                                               Subject: Re: [Digester] Method call order.                                      
                                                                                                                               
                                                                                                                               
                      03/06/2005 02:07                                                                                        
                      PM                                                                                                      
                      Please respond                                                                                          
                      to "Jakarta                                                                                              
                      Commons Users                                                                                            
                      List"                                                                                                    
                                                                                                                               
                                                                                                                               




On Fri, 2005-06-03 at 13:17 +0800, [hidden email] wrote:

> The XML I'm trying to parse:
> <Common>
>       <attributes1 attr="common_attributes1"/>
>       <attributes2 attr2="common_attributes2"/>
>       <Type1>
>             <attributes attr="subclass1_attributes"/>
>       </Type1>
>       <Type2>
>             <attributes attr="subclass2_attributes"/>
>       </Type2>
> </Common>
>
> In this scenario, I'm trying to generate an appropriate object depending
on
> whether the tag <Type1> or <Type2> appears but both must have common
> attributes "common_attributes1" & "common_attributes2" set into them.
Since
> this is my first time using Digester, I'm unaware of a way to write a
> factory at <Common> to peek deeper to get the appropriate Type class to
> load.

You can't write a factory to do that. The object must be created when
the start tag is encountered, in order for it to be available to store
attribute info on when that is found. But digester is based on SAX, so
has *no* ability to "look ahead" in the stream of data.

Some variant of your CommonLoader is the way to go I expect - though as
you have found out it isn't easy...

> So I introduced a "CommonLoader" intermediate class and wrote the
> rules as follows...
>
> <digester-rules>
>       <pattern value="Common">
>             <object-create-rule classname="CommonLoader"/>
>             <call-method-rule methodname="setCommonAttributes1"
> paramcount="1" paramtypes="java.lang.Boolean"/>
>             <call-param-rule pattern="attributes1" attrname="attr1"
> paramnumber="0"/>
>             <call-method-rule methodname="setCommonAttributes2"
> paramcount="1" />
>             <call-param-rule pattern="attributes2" attrname="attr2"
> paramnumber="0"/>
>             <pattern value="Type1">
>                   <object-create-rule classname="Type1"/>
>                   <set-next-rule methodname="setType1"/>
>                   <call-method-rule methodname="setType1Attribute"
> paramcount="1" paramtypes="java.lang.Boolean"/>
>                   <call-param-rule pattern="attributes" attrname="attr"
> paramnumber="0"/>
>             </pattern>
>             <pattern value="Type2">
>                   <object-create-rule classname="Type2"/>
>                   <set-next-rule methodname="setType2"/>
>                   <call-method-rule methodname="setType1Attribute"
> paramcount="1" paramtypes="java.lang.Boolean"/>
>                   <call-param-rule pattern="attributes" attrname="attr"
> paramnumber="0"/>
>             </pattern>
>       </pattern>
> </digester-rules>
>
> CommonLoader will have the method setType1() and setType2() and these
> methods accepts the object created (either Type1 or Type2) and then sets
> the common attributes obtained from within the <Common> tag to these Type
> objects. I require that the method setType1() and setType2() be called
last
> to ensure all the common attributes are loaded into CommonLoader before
it
> proceeds to set them into the appropriate Type object. However the order
of

> execution I got is as follows:
>
> 1.    setCommonAttributes2.
> 2.    setType1.
> 3.    setCommonAttributes1.
>
> Because setType1 as seen above is called before setCommonAttributes1,
> common_attribute1 never gets set into the object Type1.
>
> I've got a few workarounds in mind that would work, but before I proceed,
I
> need to understand as to why setCommonAttributes2() gets called based on
> the proper order while setCommonAttributes1() gets called last? Why is
the

> order not as follows?
>
> 1.    setType1
> 2.    setCommonAttributes2
> 3.    setCommonAttributes1
>
> However if I were to remove "paramtypes=java.lang.Boolean" and pass it in
> as a String then the order will be as follows:
>
> 1.    setCommonAttributes1
> 2.    setCommonAttributes2
> 3.    setType1
>
> I hope my explanation is clear and the experts out there is able to help.

Adding multiple CallMethodRule rules with the same pattern is a bad
idea. It's a design flaw in Digester, and can result in some very
unexpected behaviour. The fundamental cause is that there is just one
"parameter stack" in digester, and CallParamRule objects always operate
on the "parameter-info" structure on the top of the stack.

In your case it's not necessary to have CallMethodRule rules with the
same pattern. I suggest adding the CallMethodRule rules with the same
pattern that triggers their sole parameter:

<pattern value="Common">
  <object-create-rule ...>

  <pattern value="attributes1">
    <call-method-rule name="setCommonAttributes1" paramcount="1" .../>
    <call-param-rule attrname="attr" paramnumber="0"/>
  </pattern>

  <pattern value="attributes2">
    <call-method-rule name="setCommonAttributes2" paramcount="1" .../>
    <call-param-rule attrname="attr" paramnumber="0"/>
  </pattern>

  <pattern value="Type1">
     ....
  </pattern>
</pattern>

Regards,

Simon



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







_______________________________________________________________________________
Unencrypted electronic mail is not secure and may not be authentic.
If you have any doubts as to the contents please telephone to confirm.

This electronic transmission including any attachments is intended only
for those to whom it is addressed. It may contain copyright material or
information that is confidential, privileged or exempt from disclosure by law.
Any claim to privilege is not waived or lost by reason of mistaken transmission
of this information. If you are not the intended recipient you must not
distribute or copy this transmission and should please notify the sender.
Your costs for doing this will be reimbursed by the sender.

We do not accept liability in connection with computer virus, data corruption,
delay, interruption, unauthorised access or unauthorised amendment.
_______________________________________________________________________________


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

Reply | Threaded
Open this post in threaded view
|

Re: [Digester] Method call order.

Simon Kitching
On Fri, 2005-06-03 at 14:28 +0800, [hidden email] wrote:
> Hi Simon,
>
>       I might have missed your point, but how does this explain the
> different call order for those with "paramtypes" declared versus those
> without "paramtypes"? I'm guessing here that if paramtypes are not
> declared, it gets triggered immediately (WITHOUT being pushed into the
> stack) ..but when paramtypes are declared it gets pushed into the stack
> thus LIFO ???

I can't explain why you are seeing different behaviour when paramtypes
are explicitly declared vs not. It really seems unlikely to me, and to
be honest I suspect what you describe is not actually what is happening.
But if you can build a simple test case that demonstrates that
specifying a paramtype really can affect call order then I would
certainly be willing to look into it. Or if you provide a test that
demonstrates such an issue and a patch to fix it I will be even more
enthusiastic to look at it!

What *can* happen is that one of your calls can get skipped completely.
There's a special case for CallMethodRule when it has only one
parameter: if the parameter is not available, the call isn't made. This
is intended to avoid overriding a default value with "null" (though I
wouldn't have designed it to work that way myself). In combination with
the fact that two CallMethodRule rules associated with the same pattern
can get their params mixed up, this can mean that one of the
CallMethodRule rules gets its param set twice (then makes the call with
whatever param value got set second) while the other thinks its
parameter never got set so never makes the call at all. Mix into that
the issue that one method takes a Boolean but due to param mixups the
string that CallMethodRule tries to pass to it may not be convertible to
a Boolean and things get really complicated to diagnose. It wouldn't be
hard to misunderstand what's happening.

But all of this is not relevant anyway if my suggestion solves the issue
for you.

Regards,

Simon


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