Well, that is pretty cool. But, using Chain, I wouldn't use a filter. 

I'd define two commands, one to start the timer and one to stop the
timer. The timer would go into the context, which is thread-safe.

Then wherever we wanted to use the timer commands, we'd turn the
command into a chain (if it already wasn't).

So, if we had something like 

  <object id="issue_select" parent="BaseSelect">
                <property name="Input">
                        <list>
                                <value>issue_key</value>
                        </list>
                </property>
                <property name="Output">
                        <list>
                                <value>issue_code</value>
                                <value>issue_type</value>
                        </list>
                </property>
        </object>

we'd just make turn it into a chain 

  <object id="issue_select" parent="BaseChain">
                <property name="AddCommands">
                        <list>
                                <ref object="timer_stop" />
                                <ref object="issue_select_core" />
                                <ref object="timer_start" />
                        </list>
                </property>
  </object>

  <object id="issue_select_core" parent="BaseSelect">
                <property name=input">
                        <list>
                                <value>issue_key</value>
                        </list>
                </property>
                <property name="output">
                        <list>
                                <value>issue_code</value>
                                <value>issue_type</value>
                        </list>
                </property>
        </object>

If we wanted to time everything, we'd add them to the aforementioned
pre/post chains instead.

If such things were happening all the time, we could also add pre/post
chains to the base command processing. If the before and/or after
properties were present on the command, the processor could create a
dynamic chain to include them.

  <object id="issue_select" parent="BaseSelect">
                <property name="Input">
                        <list>
                                <value>issue_key</value>
                        </list>
                </property>
                <property name="Output">
                        <list>
                                <value>issue_code</value>
                                <value>issue_type</value>
                        </list>
                </property>
                <property name="AddBefore">
                        <list>
                        <list>
                                <ref object="timer_start" />
                        </list>
                </property>
                <property name="AddAfter">
                        <list>
                        <list>
                                <ref object="timer_stop" />
                        </list>
                </property>
        </object>

So, where WebWork added chain processing to the interceptor, we could
add interception to the chain processing. :)

My only point would be that these tools seem close enough that we
should be able to extend one to fill the role of the other.

Of course, that might be something better decided once there is a
working framework to try stuff with. :)

-T.

On 9/1/05, Don Brown <[EMAIL PROTECTED]> wrote:
> Perhaps an example would help convey what I'm trying to say:
> 
> Take a simple case where you want to processing time and log it to a file.  
> As a
> XWork interceptor, it would look like this:
> 
>    long startTime = System.currentTimeMillis();
>    String result = invocation.invoke();
>    long executionTime = System.currentTimeMillis() - startTime;
>    log.info("Execution time: "+executionTime+" ms");
> 
> Here, we define a method variable, startTime, before the rest of the 
> execution,
> then need to access it after the execution is done.
> 
> If we wanted to write this as a Filter in commons-chain, we couldn't without
> making startTime a class level variable, but then the command would no longer 
> be
> thread-safe.
> 
> Ah, but you might suggest we write that as a chain since a chain has explicit
> control over executing its children.  But then, we'd have to define the rest 
> of
> the commands within that chain and if you have multiple commands like this 
> timer
> command, they too would have to be chains:
>    process-chain
>      timer-chain
>        fooCommand
>        otherAroundCommand
>          barCommand
>      ....
> 
> This obviously has the disadvantage of deep nesting losing some of the
> readability of a simple process chain.
> 
> Therefore, my point is an interceptor chain is better suited to a scalable,
> linear process flow, while chain is better for decision points.  And neither,
> I'd argue, is well suited for a robust, configurable workflow, and this surely
> we can agree we are seeing with commons-chain in Struts Classic.
> 
> Don
> 
> BTW, I'm really enjoying this discussion and have missed these on this list.
> 
> Ted Husted wrote:
> > On 9/1/05, Don Brown <[EMAIL PROTECTED]> wrote:
> >
> >>In that case, I find interceptors more practical, as they allow
> >>you to have code before and after processing that uses method variables.  
> >>With
> >>Chain, you have to use a Filter and even then, there is no way to share
> >>variables between the two blocks of code without instance variables which 
> >>has
> >>its own problems.
> >
> >
> > First, you're doing the work, Don, and so you're welcome to make the
> > decisions :)
> >
> > Though, I don't understand is why you'd want to be restricted to two
> > blocks of code :)
> >
> > With Chain, any number of blocks of code, be they commands or chains,
> > in any combination, can be the object of the request processing.
> >
> > In OverDrive/Nexus, we do find having interceptors that surround each
> > request useful. It's not hard to define "pre" and "post" chains, and
> > then at runtime create a third chain to execute them all.
> >
> >               public void ExecuteView (IRequestContext context)
> >               {
> >                       IRequestCommand command = VerifyRequest (context);
> >                       if (context.IsNominal)
> >                       {
> >                               IChain chain = new Chain ();
> >                               if (_PreOp!=null) chain.AddCommand (_PreOp);
> >                               chain.AddCommand (command);
> >                               if (_PostOp!=null) chain.AddCommand (_PostOp);
> >                               try
> >                               {
> >                                       chain.Execute (context);
> >                               }
> >                               catch (Exception e)
> >                               {
> >                                       context.Fault = e;
> >                               }
> >                       }
> >               }
> >
> > http://svn.apache.org/viewcvs.cgi/struts/sandbox/trunk/overdrive/Nexus/Extras/Spring/Catalog.cs?view=markup
> >
> > The PreOp and PostOp chains are defined in the configuration, along
> > with everything else.
> >
> > But, we're not trying to solve the problems of navigational workflows,
> > only the problem of processing business use cases and interacting with
> > a presentation layer
> >
> > -Ted.,
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: [EMAIL PROTECTED]
> > For additional commands, e-mail: [EMAIL PROTECTED]
> >
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
> 
> 


-- 
HTH, Ted.
http://www.husted.com/poe/

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to