commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Simon Kitching <si...@ecnetwork.co.nz>
Subject Re: [digester] CallMethodRule order [bug12997] attn: Emmanuel, Craig
Date Fri, 27 Feb 2004 11:17:28 GMT
On Sat, 2004-02-28 at 11:39, Simon Kitching wrote:

> I've had a good think about your proposed patch.
> 
> The issue with your proposal is that it assumes that at the moment when
> all params are complete, the target object is on top of the digester
> object stack. This is not always true.
> 
> When the CallMethodRule's begin fires, this essentially selects the
> target object; the object on top of the object stack at the time the
> CallMethodRule's begin fires is the one on which the method must
> eventually be invoked.
> 
> With the existing rule, the CallMethodRule always fires when the object
> stack has been restored to the state it was in when the CallMethodRule
> executed its begin method.
> 
> But with your proposal, the CallMethodRule fires whenever the params are
> complete, so there's no guarantee what object will be on the top of the
> digester's object stack when that happens.
> 
> If, when the CallMethodRule "begin" fires, it could save the
> top-of-stack object somewhere and always invoke the method on that
> object then I think the issue would be resolved. But unfortunately, I
> can't see any way of doing that. The CallMethodRule can't store the
> target in a member attribute of the rule instance, because a single rule
> instance can be mapped to multiple patterns. And if you store the target
> object in any kind of stack, you get back to the same problem you had
> initially.

Hmm.. maybe I have thought of a way to do this. I'm still not entirely
sure this "call method when params available" is a good idea, but it
might be implementable as follows:

Have the digester's param stack be a stack of instances of the following
class, instead of a stack of Object[]:

  Class Invocation {  
    private CallMethodRule rule;
    private Object target;
    private Object[] params;
    private int nParamsRemainingToSet;

    public void setParam(int index, Object paramValue) {  
      params[index] = paramValue;
      --nParamsToSet;
      if (nParamsRemainingToSet == 0) { 
        rule->invokeMethod(target, params);
      }
    }
  }

The above is only rough, but gives the idea I hope. The CallMethodRule
creates one of these on begin() and pushes it onto the param stack. At
that time, it knows the target object (on top of object stack). 

I think it's also a nicer API than the current code which accesses the
raw param array.

I'm not sure whether the param stack should be regarded as an external
API for digester, though. While we can fix all param rules
(CallParamRule, ObjectParamRule, etc) we would break any variants of
these written by users if we do this. Unfortunately I think this is not
acceptable.

The question in my mind is still: what use cases require the
CallMethodRule to fire when the params are available?

One difficulty I have struct myself is that when using SetNextRule to
set up parent/child relations, the "obvious" rule ordering causes an
*uninitialised" child to be passed to the parent rather than an
initialised one because both CallMethodRule and SetNextRule do their
work in end(), and end() methods fire in the reverse order they were
added to the digester.

example:
  digester.addObjectCreate("foo/bar", Widget.class);
  digester.addCallMethodRule("foo/bar", "setId", 1);
  digester.addCallParamRule("foo/bar", 0, "id");
  digester.addSetNext("foo/bar");

this is wrong; the setNext executes before the setId method, so the
Widget is uninitialised when passed to its parent. Swapping the
CallMethodRule and SetNextRule order fixes this, but is definitely
non-intuitive.

Thoughts?

Regards,

Simon


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Mime
View raw message