You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by Jing Zhou <ji...@netspread.com> on 2003/10/03 22:53:35 UTC

Struts-chain Behavior Discussion

It looks to me that I threw a disturbing idea. Now I change
the subject for more discussions of different opinions.

Craig mentioned the "go to" statement in programming
languages and hinted it could be an evil if Chain implement
the semantics of "go to" (I just called it "jump behavior").

If we recognize Chain as a high level pattern regulator,
I would not agree such a comparison is appropriate
unless someone could convince me the following
observations are questionable.

* I studied several workflow engines (not page flow stuff, they
  manage persisted workload for people) They all implement,
  one way or another, the "jump behavior". I could not see
  they violate the OO design principles as high level
  regulators.

* Struts itself, as a MVC pattern regulator in its core, 
  implements the "go to" semantics when Action returns a
  ForwardConfig. It does a "go to" the next page, right? -:)

In another word, IMHO, low level language principles
may not be applicable to high level pattern/structure
regulators. Hope people re-think it.

I also recognize the facts that we do not want to overgrow
Chain into an xml based rule engine. It should be just chain.
But for such a simple requirement, one way is to model it
as a "if" decision (Craig way), another way is to model it
as a pseudo controller (Ted way). They are kind of 
cumbersome to use. It violates the "Simple thing should
be simple" principle - a principle that supercedes other
programming principles. The Filter thing could offer a
simple solution, but I haven't looked it in details yet.

The "jump behavior" requirement is very obvious in 
Java Server Faces Specification too. When the 
renderResponse() is called on FacesContext, the control
is transferred to the Render Response phase after
the current phase. This is another evidence of the
"jump behavior" in high level pattern regulators.

I would like people to open mind and think, if we
add a method in Chain that allows us to execute
the chain starting with a given index (currently
the starting index is 0). Will that make the thing simple?
Or the idea is still disturbing somewhere?

Jing

Netspread Carrier
http://www.netspread.com


Re: Struts-chain Behavior Discussion

Posted by Ted Husted <hu...@apache.org>.
Jing Zhou wrote:
 > * I studied several workflow engines (not page flow stuff, they
 >   manage persisted workload for people) They all implement,
 >   one way or another, the "jump behavior". I could not see
 >   they violate the OO design principles as high level
 >   regulators.

I believe Chain is suppose to be an implementation of the classic Chain 
of Responsibility pattern. Chain is something that a workflow engine 
might use, but I don't believe it is meant to a workflow engine itself.


 > The "jump behavior" requirement is very obvious in
 > Java Server Faces Specification too. When the
 > renderResponse() is called on FacesContext, the control
 > is transferred to the Render Response phase after
 > the current phase. This is another evidence of the
 > "jump behavior" in high level pattern regulators.

Using a Context to assist with a workflow process seems reasonable. The 
Command should be able to examine the state of the Context and decide 
whether they should proceed or not.

In this case, renderResponse could be the postprocess on a Filter. A 
Command returns True, the Chain ends, and the Filters begin.

For the original use-case, where you just wanted to fast-forward to the 
end, again a Filter may be the solution. Once a Command returns True, 
the Filters start firing.


 > I would like people to open mind and think, if we
 > add a method in Chain that allows us to execute
 > the chain starting with a given index (currently
 > the starting index is 0). Will that make the thing simple?
 > Or the idea is still disturbing somewhere?

Why not build another Chain? It's not a "there can only be only one" 
pattern. As many Chains can reuse as many Commands as needed.

-Ted.


Jing Zhou wrote:
> It looks to me that I threw a disturbing idea. Now I change
> the subject for more discussions of different opinions.
> 
> Craig mentioned the "go to" statement in programming
> languages and hinted it could be an evil if Chain implement
> the semantics of "go to" (I just called it "jump behavior").
> 
> If we recognize Chain as a high level pattern regulator,
> I would not agree such a comparison is appropriate
> unless someone could convince me the following
> observations are questionable.
> 
> * I studied several workflow engines (not page flow stuff, they
>   manage persisted workload for people) They all implement,
>   one way or another, the "jump behavior". I could not see
>   they violate the OO design principles as high level
>   regulators.
> 
> * Struts itself, as a MVC pattern regulator in its core, 
>   implements the "go to" semantics when Action returns a
>   ForwardConfig. It does a "go to" the next page, right? -:)
> 
> In another word, IMHO, low level language principles
> may not be applicable to high level pattern/structure
> regulators. Hope people re-think it.
> 
> I also recognize the facts that we do not want to overgrow
> Chain into an xml based rule engine. It should be just chain.
> But for such a simple requirement, one way is to model it
> as a "if" decision (Craig way), another way is to model it
> as a pseudo controller (Ted way). They are kind of 
> cumbersome to use. It violates the "Simple thing should
> be simple" principle - a principle that supercedes other
> programming principles. The Filter thing could offer a
> simple solution, but I haven't looked it in details yet.
> 
> The "jump behavior" requirement is very obvious in 
> Java Server Faces Specification too. When the 
> renderResponse() is called on FacesContext, the control
> is transferred to the Render Response phase after
> the current phase. This is another evidence of the
> "jump behavior" in high level pattern regulators.
> 
> I would like people to open mind and think, if we
> add a method in Chain that allows us to execute
> the chain starting with a given index (currently
> the starting index is 0). Will that make the thing simple?
> Or the idea is still disturbing somewhere?
> 
> Jing
> 
> Netspread Carrier
> http://www.netspread.com
> 
> 

-- 
Ted Husted,
   Junit in Action  - <http://www.manning.com/massol/>,
   Struts in Action - <http://husted.com/struts/book.html>,
   JSP Site Design  - <http://www.amazon.com/exec/obidos/ISBN=1861005512>.




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


Re: Struts-chain Behavior Discussion

Posted by Jing Zhou <ji...@netspread.com>.
----- Original Message ----- 
From: "Craig R. McClanahan" <cr...@apache.org>
To: "Struts Developers List" <st...@jakarta.apache.org>
Sent: Monday, October 06, 2003 7:25 PM
Subject: Re: Struts-chain Behavior Discussion


> I actually think this is better, because you can customize *just* the B1
> path or *just* the B2 path if you want to, without having to mess with
> MAIN at all.

I believe people should use them as they see fit. Just like choosing inner
classes or regular classes in an application, if you want to take advantage
of surrounding environments, inner classes might be more suitable. Regular
classes give you independent customization, like what you point out here.
But I do not want to say which one is better without specific goals,
because sometime people want to centralize logics and keep
them in sync, instead of specifying Class4 in three different places.

> UI workflows across requests are not what commons-chain is really for --
My message might not be that clear. I did not intend to use commons-chain
for UI workflows across requests. I am considering to design UIs to
construct chains. UIs' necessary attributes must be identified at first. The
result chains will be used in application modules (in Struts). I did
an estimation and found many use cases are just to jump to the last
command. So I am asking the list if there is a direct "jump" for those
simple use cases.

> However, it's also feasible to build branches and labels in by subclass
> CommandBase and ChainBase appropriately, instead of modify Command and
> Chain.  That would be the suggested way to prototype something.

Yes. I need to look at CommandBase and ChainBase for possible
extensions.

Jing


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


Re: Struts-chain Behavior Discussion

Posted by "Craig R. McClanahan" <cr...@apache.org>.
Jing Zhou wrote:

>----- Original Message ----- 
>From: "Craig R. McClanahan" <cr...@apache.org>
>To: "Struts Developers List" <st...@jakarta.apache.org>
>Sent: Monday, October 06, 2003 11:26 AM
>Subject: Re: Struts-chain Behavior Discussion
>
>
>  
>
>>>Looks like you are asking less while I am asking more :-)
>>>
>>>
>>>      
>>>
>>Exactly.  More == Bloat unless you really need it.  And I can't see that
>>I need it yet.
>>    
>>
>
>I did not see it until I was thinking a way to build user interfaces for
>Chain.
>If labeled commands could be regarded as implicitly defined chains, then
>we have a shorter chain-config.xml for the following MAIN chain:
>   <chains>
>     <chain name="MAIN">
>        <command jumpLabel="L1" className="Class1" />
>        <command jumpLabel="L2" className="Class2" />
>        <command label="L1" className="Class3" />
>        <command label="L2" className="Class4" />
>     </chain>
>   </chains>
>Where each labeld command defined a chain from
>that command to the end. Thus the chain L1 contains
>two commands and L2 contains one command.
>
>Currently, to achieve the same behaviors, we have to
>define two nested chains shown below. Note that the
>chain B1 is equivalent to chain L1 and B2 is equivalent
>to L2. The execution paths are identical between the
>two MAIN chains, as I explained in the other
>message. So "More" does not necessarily imply "Bloat"
>and it is not my interests to bloat any systems
>if not necessary.
>
>   <chains>
>     <chain name="MAIN">
>        <command className="Class1" branchCommand="B1" />
>        <command className="Class2" branchCommand="B2" />
>        <command className="Class3" />
>        <command className="Class4" />
>     </chain>
>     <chain name="B1">
>        <command className="Class3" />
>        <command className="Class4" />
>     </chain>
>     <chain name="B2">
>         <command className="Class4" />
>     </chain>
>   </chains>
>  
>
I actually think this is better, because you can customize *just* the B1 
path or *just* the B2 path if you want to, without having to mess with 
MAIN at all.

>  
>
>>Please build something and show it to us, instead of talking about it.
>>It won't necessarily be a "chain of responsibility" pattern any more,
>>but it might well be interesting.  However, you still haven't even shown
>>me a practical use case where the functionality you're talking about is
>>required, and you still haven't shown me how you plan to get around the
>>fragile nature of subscripts.
>>    
>>
>
>As I wrote in the other message, it should be exactly the CoR pattern
>without skipping commands.
>
Well, we already have that :-).

> Just need to do some feasibility research
>before someone could actually build it. Now we learned that
>index-based "jump behavior" is fragile. So label-based one seems to
>be the right choice.
>
And, we already have that too, by branching to labelled chains.

The remaining objection I see is to the verboseness of the 
configuration, which (as I mention above) is IMHO an advantage because 
the detailed subchains can be individually customized.

>
>Looking at the possibility to do it without changing
>core APIs is my first choice. Looks to me I need to store a label in
>context per request thread for Chain.execute(), but what about
>for non-web context is not clear to me yet (???) as well as how
>I am going to add labeled commands to a chain (???)
>
>Our real needs come from UI design requirements. We try our best
>to give end users simple ways to do simple things first, such as
>our phased validation model in Carrier. When we move to Chain,
>we have to evaluate different UI design options.
>  
>
UI workflows across requests are not what commons-chain is really for -- 
it's about designing the processing for a particular single request (in 
the case of Struts), or for decomposing the business logic generally in 
the business or persistence tiers.

However, it's also feasible to build branches and labels in by subclass 
CommandBase and ChainBase appropriately, instead of modify Command and 
Chain.  That would be the suggested way to prototype something.

>  
>
>>Craig
>>
>>    
>>
Craig

>Jing
>Netspread Carrier
>http://www.netspread.com
>
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: struts-dev-unsubscribe@jakarta.apache.org
>For additional commands, e-mail: struts-dev-help@jakarta.apache.org
>  
>



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


Re: Struts-chain Behavior Discussion

Posted by Jing Zhou <ji...@netspread.com>.
----- Original Message ----- 
From: "Craig R. McClanahan" <cr...@apache.org>
To: "Struts Developers List" <st...@jakarta.apache.org>
Sent: Monday, October 06, 2003 11:26 AM
Subject: Re: Struts-chain Behavior Discussion


> >
> >Looks like you are asking less while I am asking more :-)
> >
> >
>
> Exactly.  More == Bloat unless you really need it.  And I can't see that
> I need it yet.

I did not see it until I was thinking a way to build user interfaces for
Chain.
If labeled commands could be regarded as implicitly defined chains, then
we have a shorter chain-config.xml for the following MAIN chain:
   <chains>
     <chain name="MAIN">
        <command jumpLabel="L1" className="Class1" />
        <command jumpLabel="L2" className="Class2" />
        <command label="L1" className="Class3" />
        <command label="L2" className="Class4" />
     </chain>
   </chains>
Where each labeld command defined a chain from
that command to the end. Thus the chain L1 contains
two commands and L2 contains one command.

Currently, to achieve the same behaviors, we have to
define two nested chains shown below. Note that the
chain B1 is equivalent to chain L1 and B2 is equivalent
to L2. The execution paths are identical between the
two MAIN chains, as I explained in the other
message. So "More" does not necessarily imply "Bloat"
and it is not my interests to bloat any systems
if not necessary.

   <chains>
     <chain name="MAIN">
        <command className="Class1" branchCommand="B1" />
        <command className="Class2" branchCommand="B2" />
        <command className="Class3" />
        <command className="Class4" />
     </chain>
     <chain name="B1">
        <command className="Class3" />
        <command className="Class4" />
     </chain>
     <chain name="B2">
         <command className="Class4" />
     </chain>
   </chains>

> Please build something and show it to us, instead of talking about it.
> It won't necessarily be a "chain of responsibility" pattern any more,
> but it might well be interesting.  However, you still haven't even shown
> me a practical use case where the functionality you're talking about is
> required, and you still haven't shown me how you plan to get around the
> fragile nature of subscripts.

As I wrote in the other message, it should be exactly the CoR pattern
without skipping commands. Just need to do some feasibility research
before someone could actually build it. Now we learned that
index-based "jump behavior" is fragile. So label-based one seems to
be the right choice.

Looking at the possibility to do it without changing
core APIs is my first choice. Looks to me I need to store a label in
context per request thread for Chain.execute(), but what about
for non-web context is not clear to me yet (???) as well as how
I am going to add labeled commands to a chain (???)

Our real needs come from UI design requirements. We try our best
to give end users simple ways to do simple things first, such as
our phased validation model in Carrier. When we move to Chain,
we have to evaluate different UI design options.

>
> Craig
>

Jing
Netspread Carrier
http://www.netspread.com


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


Re: Struts-chain Behavior Discussion

Posted by "Craig R. McClanahan" <cr...@apache.org>.
Jing Zhou wrote:

>----- Original Message ----- 
>From: "Ted Husted" <hu...@apache.org>
>To: "Struts Developers List" <st...@jakarta.apache.org>
>Sent: Saturday, October 04, 2003 10:37 AM
>Subject: Re: Struts-chain Behavior Discussion
>
>
>  
>
>>Jing Zhou wrote:
>>    
>>
>>>For me, "Simple thing should be simple" is the
>>>top rule that supersedes any programming practices. 
>>>      
>>>
>>Some of might say that this *is* a programming practice. Some might also 
>>couch it as start with "the simplest thing that can possibly work", and 
>>then let practice be your guide.
>>    
>>
>
>Only when the experiences they primarily have are coding (there are a lot
>of other fields where the same rule is applied to).
>
>  
>
>>>* If I have 15 commands that needs to jump to the last one in a chain,
>>>   if the branch way is used, then the last command must be repeatedly
>>>  defined16 times in the config file. It loses the grace in expressions
>>>  (although the sample config file does not reveal this problem).
>>>      
>>>
>>Each Command can examine the Context to see if it can handle the current 
>>state. If it can't then it returns false, and processing continues. You 
>>don't need to "jump", you need a Command to define the appropriate state 
>>in your Context.
>>
>>The fundamental problem might be viewing the Chain as the brains of the 
>>operation. It isn't. The Chain is just a composite of Commands. The 
>>Context manages state, and so the Context is where any decision making 
>>occurs.
>>
>>
>>    
>>
>>>* The "branch behavior" and "jump behavior" are complementary to
>>>   to each other in theory. Repeatedly executing a set of commands in
>>>   a chain can not be done gracefully in a *extreme* configurable
>>>   chain.
>>>      
>>>
>>Yes, it's possible that the branch behavior might not be the best way to 
>>go. I suspect that it might be better if a Command did not call other 
>>Commands, either directly or through the Catalog. But, I do think we 
>>should leave that door open so that people can experiment with this 
>>extension. I know in similar implementations, I often found myself 
>>having (the equivalent of) Commands calling Commands. But those 
>>implementations did not have a Chain to work with, and once we have more 
>>experience working with a real Chains, other strategies may become 
>>evident. I believe that at some point we may be able to dispense with 
>>branch behavior, so that very little happens behind the scenes. Or maybe 
>>not. Practice will dictate.
>>    
>>
>
>Looks like you are asking less while I am asking more :-)
>  
>

Exactly.  More == Bloat unless you really need it.  And I can't see that 
I need it yet.

>  
>
>>>* If in the end, the fundamental APIs do not want to deal with
>>>   "jump behavior", I still could not successfully implement an
>>>   extended Chain to make up the capability. From the original
>>>   publication about the Chain of Responsibility, it does not
>>>   dictate "jump behavior" is prohibited or "branch behavior" is
>>>   only allowed. In my world view, the three behaviors are
>>>   equally important: "sequence behavior", "branch behavior",
>>>   and "jump behavior" in an extreme configurable chain.
>>>      
>>>
>>IMHO, these behaviors out of scope for an implementation of the Chain of 
>>Responsibility pattern. Many implementations don't even return false or 
>>have the Filter backdoor. These are optimizations Craig made to help 
>>with resource-intensive operations. In many implementations, every 
>>Command on the Chain is visited, and there may not even be a guarantee 
>>that any of the Commands handles the request. I don't see "jump 
>>behavior" as an essential part of the CoR "world view". The 
>>boolean/Filter behavior is a stretch as it is, and it is probably as far 
>>we can go and still call it a GoF CoR.
>>    
>>
>
>Neither "sequence behavior" nor "branch behavior" are described
>as essential parts of the CoR "world view". Since the three behaviors
>are orthogonal to each other and commons-chain implements two
>of them, thus in theory, it is *in-complete*. That is the research
>direction I would like to point out to the community that we might
>be able to complete it some how.
>
Please build something and show it to us, instead of talking about it.  
It won't necessarily be a "chain of responsibility" pattern any more, 
but it might well be interesting.  However, you still haven't even shown 
me a practical use case where the functionality you're talking about is 
required, and you still haven't shown me how you plan to get around the 
fragile nature of subscripts.

>
>For some applications, just "sequence behavior" is enough as you
>mentioned before. But from the research point of view,
>it has very little gain than using a single RequestProcessor. Since
>commons-chain is also designed to be used in other environments,
>for example, in business tiers, the community should put more efforts
>to extract maximum possible functionality out of Chain.
>  
>
Actually, our very own use case (RequestProcessor) is a perfect example 
of why using a chain instead of a base RequestProcessor class -- with 
nothing else -- is still more powerful.  Consider the dilemma I was in 
trying to implement the struts-faces library:

* I needed to implement my own RequestProcessor subclass to
  override some of the base behaviors.

* I want to integrate support for Tiles, which also requires its
  own RequestProcessor subclass, but not require it.

* Java doesn't support multiple inheritance.

With CoR, this is trivially solved by providing different standard 
chains that interweave the various commands as necessary (Struts 
standalone, Tiles standalone, Struts+Faces, Struts+Tiles, and 
Struts+Tiles+Faces).

>  
>
>>-Ted.
>>
>>    
>>
>
>Jing
>  
>
Craig

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



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


Re: Struts-chain Behavior Discussion

Posted by Jing Zhou <ji...@netspread.com>.
----- Original Message ----- 
From: "Ted Husted" <hu...@apache.org>
To: "Struts Developers List" <st...@jakarta.apache.org>
Sent: Saturday, October 04, 2003 10:37 AM
Subject: Re: Struts-chain Behavior Discussion


> Jing Zhou wrote:
> > For me, "Simple thing should be simple" is the
> > top rule that supersedes any programming practices. 
> 
> Some of might say that this *is* a programming practice. Some might also 
> couch it as start with "the simplest thing that can possibly work", and 
> then let practice be your guide.

Only when the experiences they primarily have are coding (there are a lot
of other fields where the same rule is applied to).

> 
> > * If I have 15 commands that needs to jump to the last one in a chain,
> >    if the branch way is used, then the last command must be repeatedly
> >   defined16 times in the config file. It loses the grace in expressions
> >   (although the sample config file does not reveal this problem).
> 
> Each Command can examine the Context to see if it can handle the current 
> state. If it can't then it returns false, and processing continues. You 
> don't need to "jump", you need a Command to define the appropriate state 
> in your Context.
> 
> The fundamental problem might be viewing the Chain as the brains of the 
> operation. It isn't. The Chain is just a composite of Commands. The 
> Context manages state, and so the Context is where any decision making 
> occurs.
> 
> 
> > * The "branch behavior" and "jump behavior" are complementary to
> >    to each other in theory. Repeatedly executing a set of commands in
> >    a chain can not be done gracefully in a *extreme* configurable
> >    chain.
> 
> Yes, it's possible that the branch behavior might not be the best way to 
> go. I suspect that it might be better if a Command did not call other 
> Commands, either directly or through the Catalog. But, I do think we 
> should leave that door open so that people can experiment with this 
> extension. I know in similar implementations, I often found myself 
> having (the equivalent of) Commands calling Commands. But those 
> implementations did not have a Chain to work with, and once we have more 
> experience working with a real Chains, other strategies may become 
> evident. I believe that at some point we may be able to dispense with 
> branch behavior, so that very little happens behind the scenes. Or maybe 
> not. Practice will dictate.

Looks like you are asking less while I am asking more :-)

> > * If in the end, the fundamental APIs do not want to deal with
> >    "jump behavior", I still could not successfully implement an
> >    extended Chain to make up the capability. From the original
> >    publication about the Chain of Responsibility, it does not
> >    dictate "jump behavior" is prohibited or "branch behavior" is
> >    only allowed. In my world view, the three behaviors are
> >    equally important: "sequence behavior", "branch behavior",
> >    and "jump behavior" in an extreme configurable chain.
> 
> IMHO, these behaviors out of scope for an implementation of the Chain of 
> Responsibility pattern. Many implementations don't even return false or 
> have the Filter backdoor. These are optimizations Craig made to help 
> with resource-intensive operations. In many implementations, every 
> Command on the Chain is visited, and there may not even be a guarantee 
> that any of the Commands handles the request. I don't see "jump 
> behavior" as an essential part of the CoR "world view". The 
> boolean/Filter behavior is a stretch as it is, and it is probably as far 
> we can go and still call it a GoF CoR.

Neither "sequence behavior" nor "branch behavior" are described
as essential parts of the CoR "world view". Since the three behaviors
are orthogonal to each other and commons-chain implements two
of them, thus in theory, it is *in-complete*. That is the research
direction I would like to point out to the community that we might
be able to complete it some how.

For some applications, just "sequence behavior" is enough as you
mentioned before. But from the research point of view,
it has very little gain than using a single RequestProcessor. Since
commons-chain is also designed to be used in other environments,
for example, in business tiers, the community should put more efforts
to extract maximum possible functionality out of Chain.

> 
> -Ted.
> 

Jing

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


Re: Struts-chain Behavior Discussion

Posted by Ted Husted <hu...@apache.org>.
Jing Zhou wrote:
> For me, "Simple thing should be simple" is the
> top rule that supersedes any programming practices. 

Some of might say that this *is* a programming practice. Some might also 
couch it as start with "the simplest thing that can possibly work", and 
then let practice be your guide.


> * If I have 15 commands that needs to jump to the last one in a chain,
>    if the branch way is used, then the last command must be repeatedly
>   defined16 times in the config file. It loses the grace in expressions
>   (although the sample config file does not reveal this problem).

Each Command can examine the Context to see if it can handle the current 
state. If it can't then it returns false, and processing continues. You 
don't need to "jump", you need a Command to define the appropriate state 
in your Context.

The fundamental problem might be viewing the Chain as the brains of the 
operation. It isn't. The Chain is just a composite of Commands. The 
Context manages state, and so the Context is where any decision making 
occurs.


> * The "branch behavior" and "jump behavior" are complementary to
>    to each other in theory. Repeatedly executing a set of commands in
>    a chain can not be done gracefully in a *extreme* configurable
>    chain.

Yes, it's possible that the branch behavior might not be the best way to 
go. I suspect that it might be better if a Command did not call other 
Commands, either directly or through the Catalog. But, I do think we 
should leave that door open so that people can experiment with this 
extension. I know in similar implementations, I often found myself 
having (the equivalent of) Commands calling Commands. But those 
implementations did not have a Chain to work with, and once we have more 
experience working with a real Chains, other strategies may become 
evident. I believe that at some point we may be able to dispense with 
branch behavior, so that very little happens behind the scenes. Or maybe 
not. Practice will dictate.


>> * Basing index values for "jump behavior" is fundamentally flawed.
>    I was aware of that. It has the similar problems as in the pseudo
>    controllers (where each commands in between must honor a flag).
>    To be honest, I have not used commons-chain yet, this is just
>    an analysis from what I understand so far. The potential problems
>    here is about the index-based binding in the Chain interface.
>    The Chain interface bind commands based on the order the
>    commands are added. So we can not jump to a logically named
>    command in a chain. This makes the index-based jump the only
>    possible way.

This is not a case of Command looking for flags, but a case of the 
Command examining the state of the Context and deciding whether the 
current Context applies to them or not. It is perfectly  normal and 
expected for many Command to be called but to do nothing (and return 
false). Jumping is not something you need to do externally.

In fact, I would say that avoiding jumps is why we have the Chain of 
Responsibility in the first place. We don't want to work that hard. We 
want to hand the Context to the Command (or Chain of Commands), and let 
the Commands do what they will.

For more on the intent of the CoR, see the Design Patterns book.

It's possible that you are not imagining the Chains to finely enough 
grained. An application can use as many Chains (or Catalogs) as needed. 
A service method (like a Struts Action) can determine which Chain to 
call from which Catalog under which circumstances. The need for a "jump 
behavior" might imply that the Chain is too coarsely grained and needs 
to be refactored.

If this thread were based on an actual use-case with a real Chain and 
real Commands, then we could look at alternative ways to implement the 
Chain. But since it isn't, we can't.


> * If in the end, the fundamental APIs do not want to deal with
>    "jump behavior", I still could not successfully implement an
>    extended Chain to make up the capability. From the original
>    publication about the Chain of Responsibility, it does not
>    dictate "jump behavior" is prohibited or "branch behavior" is
>    only allowed. In my world view, the three behaviors are
>    equally important: "sequence behavior", "branch behavior",
>    and "jump behavior" in an extreme configurable chain.

IMHO, these behaviors out of scope for an implementation of the Chain of 
Responsibility pattern. Many implementations don't even return false or 
have the Filter backdoor. These are optimizations Craig made to help 
with resource-intensive operations. In many implementations, every 
Command on the Chain is visited, and there may not even be a guarantee 
that any of the Commands handles the request. I don't see "jump 
behavior" as an essential part of the CoR "world view". The 
boolean/Filter behavior is a stretch as it is, and it is probably as far 
we can go and still call it a GoF CoR.



> * There are more issues. But I get to stop here for a clear view
>    of my thinking. Again, this is derived from what I estimated
>    from the codes. If any thing incorrect or there is already
>    a solution to the problem, I'd be interested. At least, I
>    have more understanding to commons-chain now :-)

The best solution would be to roll up your sleeves and start using the 
CoR in your own implementations. The pattern is very well known and well 
documented. The Gang of Four has already done the whiteboard for us. We 
are past the point of "armchair engineering". IMHO, any changes to the 
API should be based on concrete needs and live use-cases, rather than 
speculation.

As I believe Craig mentioned, this is open source. If you think Chain 
should be extended in a certain way, then go ahead extend it, and let us 
know how it turns out.

-Ted.



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


Re: Struts-chain Behavior Discussion

Posted by Jing Zhou <ji...@netspread.com>.
----- Original Message ----- 
From: "Craig R. McClanahan" <cr...@apache.org>
To: "Struts Developers List" <st...@jakarta.apache.org>
Sent: Friday, October 03, 2003 7:09 PM
Subject: Re: Struts-chain Behavior Discussion


> Jing Zhou wrote:
> 
> >It looks to me that I threw a disturbing idea. Now I change
> >the subject for more discussions of different opinions.
> >
> >Craig mentioned the "go to" statement in programming
> >languages and hinted it could be an evil if Chain implement
> >the semantics of "go to" (I just called it "jump behavior").
> >
> >If we recognize Chain as a high level pattern regulator,
> >I would not agree such a comparison is appropriate
> >unless someone could convince me the following
> >observations are questionable.
> >
> >* I studied several workflow engines (not page flow stuff, they
> >  manage persisted workload for people) They all implement,
> >  one way or another, the "jump behavior". I could not see
> >  they violate the OO design principles as high level
> >  regulators.
> >  
> >
> You seem to be assuming that commons-chain is, or is intended to be, a 
> workflow engine.  It's not.  It's fundamental plumbing that might or 
> might not be used in the creation of a workflow engine, but would 
> certainly not be the only API exposed to users.

I did not assume that commons-chain is (or intended to be) a
workflow engine here. The two observations (including the Struts
one below) tell me that there is nothing wrong to implement
"jump behavior" in high level pattern regulators (or systems). They are
not that kind of "evils" we see the "go to" in programming languages.

> 
> >* Struts itself, as a MVC pattern regulator in its core, 
> >  implements the "go to" semantics when Action returns a
> >  ForwardConfig. It does a "go to" the next page, right? -:)
> >
 
> Thus, Filter doesn't help you deal with control flow.

Got it clear. Thanks for the details.

> It's not just an issue of simplicity, it's an issue of necessity.  You 
> haven't yet shown me a use case where commons-chain is the right design 
> pattern for implementing something, but it cannot be done (or cannot be 
> done gracefully) without the "start at index" or "skip this step" 
> capability. 
> Additionally, basing starting and/or stopping points on indexes into the 
> chain is horribly fragile -- as soon as I add or remove steps elsewhere 
> in the chain, I've just broken your logic, and introduced a bug in 
> something I did not directly change.  That would be bad, so I'm also 
> opposed to the idea on technical grounds.
> 
> Finally, even if you do have a use case that needs this capability, 
> there's nothing stopping you from implementing an extended Chain that 
> does it.  I contend we should not put anything like that into the 
> fundamental APIs unless it's absolutely vital.
> 

Evaluating a requirement to see if it is vital or not depends on how you
order the rules to follow. For me, "Simple thing should be simple" is the
top rule that supersedes any programming practices. Here are the
issues I could see:

* If I have 15 commands that needs to jump to the last one in a chain,
   if the branch way is used, then the last command must be repeatedly
  defined16 times in the config file. It loses the grace in expressions
  (although the sample config file does not reveal this problem).

* The "branch behavior" and "jump behavior" are complementary to
   to each other in theory. Repeatedly executing a set of commands in
   a chain can not be done gracefully in a *extreme* configurable
   chain.

* Basing index values for "jump behavior" is fundamentally flawed.
   I was aware of that. It has the similar problems as in the pseudo
   controllers (where each commands in between must honor a flag).
   To be honest, I have not used commons-chain yet, this is just
   an analysis from what I understand so far. The potential problems
   here is about the index-based binding in the Chain interface.
   The Chain interface bind commands based on the order the
   commands are added. So we can not jump to a logically named
   command in a chain. This makes the index-based jump the only
   possible way.

* If in the end, the fundamental APIs do not want to deal with
   "jump behavior", I still could not successfully implement an
   extended Chain to make up the capability. From the original
   publication about the Chain of Responsibility, it does not
   dictate "jump behavior" is prohibited or "branch behavior" is
   only allowed. In my world view, the three behaviors are
   equally important: "sequence behavior", "branch behavior",
   and "jump behavior" in an extreme configurable chain.

* There are more issues. But I get to stop here for a clear view
   of my thinking. Again, this is derived from what I estimated
   from the codes. If any thing incorrect or there is already
   a solution to the problem, I'd be interested. At least, I
   have more understanding to commons-chain now :-)

> Craig
> 

Jing


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


Re: Struts-chain Behavior Discussion

Posted by Ted Husted <hu...@apache.org>.
Craig R. McClanahan wrote (10/4/2003 2:02 PM):
> So, implementing this as a single chain would require ValidateActionForm 
> to the success/failure state of the validation into the Context -- easy 
> to do -- and three commands must now (inside their implementation -- the 
> Chain does not know anything about this) surround their current behavior 
> in an "if" statement, which means that they have to know the location of 
> the state information that was saved (slight increase in coupling), and 
> they get processed by the Chain even if they are not relevant (very 
> minor performance impact; almost never enough of a concern to worry 
> about).  But it would definitely work.

Yes, the current implementation trades coupling the Commands to the 
Context with coupling this Command to the Catalog, which I agree is a 
fair trade under the circumstances. But, TANSTAFL, coupling does 
increase somewhere, it's just a matter of choosing your battles. :)

Based on using the Command strategy in other implementations, I would 
guess that people retrofitting code streams (as we are doing here) may 
often find it simplest to nest Commands. Meanwhlie, people building the 
business logic from scratch may tend to make more use of the Context so 
that is easier for Commands to skip themselves.

-Ted.



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


Re: Possible Struts/StrutsTestCase bug

Posted by Mark McBride <ma...@llnl.gov>.
Thank you for you quick response.

I'll get the same test case set up with tomcat and see how it goes.

Thanks!

-Mark

At 09:16 PM 10/7/2003 -0700, David Graham wrote:
>--- Mark McBride <ma...@llnl.gov> wrote:
> > I may have found a problem using Struts/StrutsTestCase with OC4J(9.0.4).
> >
> > Background: I'm running a StrutsTestCase that works in Resin 2.x but
> > when
> > ran in OC4J I get a NullPointerException from
> > org.apache.struts.util.RequestUtils.java line 1806. The problem I found
> > with both the RequestUtils.java and CactusStrutsTestCase.java are
> > illustrated below.
> >
> > The problem can be found in two places. The first is in
> > CactusStrutsTestCase.java line 417:
> > String moduleName = (String)
> > request.getAttribute(Common.INCLUDE_SERVLET_PATH);
> > if (moduleName.endsWith("/"))
> >      moduleName = moduleName.substring(0,moduleName.lastIndexOf("/"));
> >
> > In resin 2.X this runs correctly with moduleName being initialized to ""
> >
> > even if the attribute is not found.
> > In oc4j 9.0.4 request.getAttribute returns "null" when an attribute is
> > not
> > found. When moduleName.endsWith gets executed a NullPointerException is
> > thrown.
> >
> > The second is in org.apache.struts.util.RequestUtils.java introduced in
> > line 1783 blows up on line 1806:
> > On line 1783 (same fundamental problem as the first error):
> > String matchPath = (String)
> > request.getAttribute(RequestProcessor.INCLUDE_SERVLET_PATH);
> > // matchPath is set to "" in resin matchPath is null in oc4j
> > if (matchPath == null) {
> >      matchPath = request.getServletPath();
> >     }
> >   return getModuleName( matchPath, context);
> >
> > Both calls to request.getXXX return an empty string in resin. In oc4j
> > null
> > is returned.
> > The error is surfaced on line 1806:
> > while (prefix.equals("") && ((lastSlash = matchPath.lastIndexOf("/")) >
> > 0)) {
> >
> > Since the call to getModuleName passes in null, matchPath.lastIndexOf
> > throws a NullPointerException.
> >
> > Good news is that this is open-source and I can hack the code for myself
> >
> > =). I'm curious of all the other sections of code in struts that make
> > the
> > assumption that the request object will return an instantiated object
> > and
> > not "null".? It appears that the servlet 2.3 specification specifies
> > that
> > returning null is the correct servlet implementation.
> >
>http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletRequest.html#getAttribute(java.lang.String)
> >
> > What is the best way to file bugs for both struts and strutstestcase?
>
>Struts bugs are entered into bugzilla: http://nagoya.apache.org/bugzilla/
>
>StrutsTestCase is an independent SourceForge project.
>
>Both of the containers you mentioned are non-free which really limits what
>we can do to test the problem.  I believe the majority of us are using
>Tomcat because it's the free reference implementation of the Servlet and
>JSP specs.  Tomcat should implement the specs *exactly* so if it fails
>there, it's most likely a Struts bug.
>
>David
>
> >
> > Thanks in advance!
> >
> > -Mark
> >
>
>
>__________________________________
>Do you Yahoo!?
>The New Yahoo! Shopping - with improved product search
>http://shopping.yahoo.com
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: struts-dev-unsubscribe@jakarta.apache.org
>For additional commands, e-mail: struts-dev-help@jakarta.apache.org

Mark T. McBride
Computer Scientist
Lawrence Livermore National Laboratory
http://www.llnl.gov

Office: (925) 423-1627
Fax: (925) 423-3140

Re: Possible Struts/StrutsTestCase bug

Posted by David Graham <gr...@yahoo.com>.
--- Mark McBride <ma...@llnl.gov> wrote:
> I may have found a problem using Struts/StrutsTestCase with OC4J(9.0.4).
> 
> Background: I'm running a StrutsTestCase that works in Resin 2.x but
> when 
> ran in OC4J I get a NullPointerException from 
> org.apache.struts.util.RequestUtils.java line 1806. The problem I found 
> with both the RequestUtils.java and CactusStrutsTestCase.java are 
> illustrated below.
> 
> The problem can be found in two places. The first is in 
> CactusStrutsTestCase.java line 417:
> String moduleName = (String)
> request.getAttribute(Common.INCLUDE_SERVLET_PATH);
> if (moduleName.endsWith("/"))
>      moduleName = moduleName.substring(0,moduleName.lastIndexOf("/"));
> 
> In resin 2.X this runs correctly with moduleName being initialized to ""
> 
> even if the attribute is not found.
> In oc4j 9.0.4 request.getAttribute returns "null" when an attribute is
> not 
> found. When moduleName.endsWith gets executed a NullPointerException is
> thrown.
> 
> The second is in org.apache.struts.util.RequestUtils.java introduced in 
> line 1783 blows up on line 1806:
> On line 1783 (same fundamental problem as the first error):
> String matchPath = (String) 
> request.getAttribute(RequestProcessor.INCLUDE_SERVLET_PATH);
> // matchPath is set to "" in resin matchPath is null in oc4j
> if (matchPath == null) {
>      matchPath = request.getServletPath();
>     }
>   return getModuleName( matchPath, context);
> 
> Both calls to request.getXXX return an empty string in resin. In oc4j
> null 
> is returned.
> The error is surfaced on line 1806:
> while (prefix.equals("") && ((lastSlash = matchPath.lastIndexOf("/")) >
> 0)) {
> 
> Since the call to getModuleName passes in null, matchPath.lastIndexOf 
> throws a NullPointerException.
> 
> Good news is that this is open-source and I can hack the code for myself
> 
> =). I'm curious of all the other sections of code in struts that make
> the 
> assumption that the request object will return an instantiated object
> and 
> not "null".? It appears that the servlet 2.3 specification specifies
> that 
> returning null is the correct servlet implementation.
>
http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletRequest.html#getAttribute(java.lang.String)
> 
> What is the best way to file bugs for both struts and strutstestcase?

Struts bugs are entered into bugzilla: http://nagoya.apache.org/bugzilla/

StrutsTestCase is an independent SourceForge project.

Both of the containers you mentioned are non-free which really limits what
we can do to test the problem.  I believe the majority of us are using
Tomcat because it's the free reference implementation of the Servlet and
JSP specs.  Tomcat should implement the specs *exactly* so if it fails
there, it's most likely a Struts bug.

David

> 
> Thanks in advance!
> 
> -Mark
> 


__________________________________
Do you Yahoo!?
The New Yahoo! Shopping - with improved product search
http://shopping.yahoo.com

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


Possible Struts/StrutsTestCase bug

Posted by Mark McBride <ma...@llnl.gov>.
I may have found a problem using Struts/StrutsTestCase with OC4J(9.0.4).

Background: I'm running a StrutsTestCase that works in Resin 2.x but when 
ran in OC4J I get a NullPointerException from 
org.apache.struts.util.RequestUtils.java line 1806. The problem I found 
with both the RequestUtils.java and CactusStrutsTestCase.java are 
illustrated below.

The problem can be found in two places. The first is in 
CactusStrutsTestCase.java line 417:
String moduleName = (String) request.getAttribute(Common.INCLUDE_SERVLET_PATH);
if (moduleName.endsWith("/"))
     moduleName = moduleName.substring(0,moduleName.lastIndexOf("/"));

In resin 2.X this runs correctly with moduleName being initialized to "" 
even if the attribute is not found.
In oc4j 9.0.4 request.getAttribute returns "null" when an attribute is not 
found. When moduleName.endsWith gets executed a NullPointerException is thrown.

The second is in org.apache.struts.util.RequestUtils.java introduced in 
line 1783 blows up on line 1806:
On line 1783 (same fundamental problem as the first error):
String matchPath = (String) 
request.getAttribute(RequestProcessor.INCLUDE_SERVLET_PATH);
// matchPath is set to "" in resin matchPath is null in oc4j
if (matchPath == null) {
     matchPath = request.getServletPath();
    }
  return getModuleName( matchPath, context);

Both calls to request.getXXX return an empty string in resin. In oc4j null 
is returned.
The error is surfaced on line 1806:
while (prefix.equals("") && ((lastSlash = matchPath.lastIndexOf("/")) > 0)) {

Since the call to getModuleName passes in null, matchPath.lastIndexOf 
throws a NullPointerException.

Good news is that this is open-source and I can hack the code for myself 
=). I'm curious of all the other sections of code in struts that make the 
assumption that the request object will return an instantiated object and 
not "null".? It appears that the servlet 2.3 specification specifies that 
returning null is the correct servlet implementation.
http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletRequest.html#getAttribute(java.lang.String)

What is the best way to file bugs for both struts and strutstestcase?

Thanks in advance!

-Mark

Re: Struts-chain Behavior Discussion

Posted by Jing Zhou <ji...@netspread.com>.
> >I could be convinced if I see a possible mechanism that deals with
> >the command coupling problem and state storage problem.
> >  
> >
> Jing, it is sounding more and more like what you want is a scripting 
> control flow language expressed in XML.  That is absolutely, totally, 
> *not* what commons-chain is about.  Feel free to invent your own package 
> for this purpose.  Feel free to popularize it all you want.  You're even 
> welcome to say "this is an extension to commons-chain that supports 
> branches and labels".  But commons-chain itself is going to stay focused 
> on the pure CoR pattern, which has absolutely no notion of branches or 
> labels in the fundamental APIs.  Such things, therefore, do not belong 
> in the fundamental commons-chain APIs.
> 
> I'm not going to bother to respond to any further discussion along this 
> line -- as far as I'm concerned, the case for adding branches and labels 
> has failed to illustrate that it has any technical merit (for 
> commons-chain), and I'm not interested in spending any more time 
> discussing it.  What you do in your own projects (open source or not) 
> is, of course, totally up to you.

I would agree we put the discussion aside because the idea
behind "branch behavior" is premature. I also agree the rational that
we do it all the way or do not do it at all. The "branch behavior"
gives us something that is done only half way.

When you roll back (no branches), the command coupling problem
through states is *my* (the chain designer) problem or is *my* fault
by definition if the new command is not correctly coupled with other
commands. This raises another question: How many chances
this command could be reused in another chain in general? I do not
believe we are going to have a clear answer very soon. Practice might
tell us. So, I put it on hold for further study of the chain's behaviors
until more feedback come from practices.

> Craig

Jing


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


Re: Struts-chain Behavior Discussion

Posted by "Craig R. McClanahan" <cr...@apache.org>.
Jing Zhou wrote:

>----- Original Message ----- 
>From: "Craig R. McClanahan" <cr...@apache.org>
>To: "Struts Developers List" <st...@jakarta.apache.org>
>Sent: Tuesday, October 07, 2003 2:22 PM
>Subject: Re: Struts-chain Behavior Discussion
>
>
>  
>
>>>You do not need to determine Class4 was always run or not,
>>>actually it is determined at runtime. Its definition is included
>>>in every labeled chain by default.
>>>
>>>      
>>>
>>It is absolutely necessary to understand the control flow if you want to
>>customize it.  The above would support all of the following flows
>>(assuming that no command returns true prematurely):
>>* Class1 - Class2 - Class3 - Class4
>>* Class1 - Class3 - Class4
>>* Class1 - Class2 - Class4
>>
>>Now, if I want to add a new step that has to occur before Class3, but is
>>ONLY executed if Class3 will be executed, how do I do that?  I have to
>>change which command gets label L1, which is bad for the same reason
>>that "goto" in programming languages is bad.
>>    
>>
>
>You could easily assign the label L1 to the new command before Class3
>in the chain. A chain definition is normally very very small (5-30 lines)
>comparing with programs (up to 8000 or more lines). I do not see any
>difficulties to manipulate such a small section. Note that the thing we are
>dealing with is a config file, not a program (with a "go to" from line 67 to
>line 7598 :-)
>
>  
>
>>>The idea is that you do not have to define a separate chain else where
>>>if you could re-use a labeled chain in the current chain definition.
>>>You could also ignore  labels if any, just use the chain as is.
>>>
>>>
>>>      
>>>
>>If you're going to (potentially) ignore the labels and branches, why
>>have them in the first place?
>>    
>>
>
>In the example, the L1 labeled chain is invoked by Class1 if it returns
>false. If you do not need the particular L1 labeled chain in the current
>chain definition, you could ignore it. But the label could serve as
>an entry point for other chains outside the scope to invoke the L1
>labeled chain if they find it useful.
>
>  
>
>>Or, to put it differently, conditional behavior should be a feature of
>>the Command implementation ("is the world in the correct state for me to
>>perform this action?").  If the current state is not correct, it should
>>just return false to let the chain continue.  That's why a change based
>>on Ted's suggestion:
>>
>>(1) LookupCommand
>>(2) ExceptionCatcher
>>(3) SelectLocale
>>(4) SelectAction
>>(5) CreateActionForm
>>(6) PopulateActionForm
>>(7) ValidateActionForm (must save state in the Context)
>>(NEW) SelectInput [skip if validation succeeded]
>>(8) CreateAction [skip if validation failed]
>>(9) ExecuteAction [skip if validation failed]
>>(10) PerformForward
>>
>>is actually the cleanest overall approach.  The user should not have to
>>even *know* what conditions the commands care about to determine whether
>>they are executed.  Thus, you would end up with a clean and simple chain
>>definition:
>>
>><chain id="request-processor">
>>  <command class="LookupCommand"/>
>>  <command class="ExceptionCatcher"/>
>>  <command class="SelectLocale"/>
>>  <command class="SelectAction"/>
>>  <command class="CreateActionForm"/>
>>  <command class="PopulateActionForm"/>
>>  <command class="ValidateActionForm"/>
>>  <command class="SelectInput"/>
>>  <command class="CreateAction"/>
>>  <command class="ExecuteAction"/>
>>  <command class="PerformForward"/>
>></chain>
>>
>>Now, if I want to insert something that always happens before
>>ValidateActionForm, I know exactly where it goes.  I don't have to worry
>>about whether ValidateActionForm is going to branch or skip, because
>>it's not ... SelectInput and friends decide for themselves whether they
>>are relevant.
>>
>>OK, I've convinced myself that this is the right approach :-).  So I'll
>>likely be changing struts-chain to this tonight, and adding the
>>appropriate mechanisms for ValidateActionForm to pass on the success or
>>failure state information.
>>    
>>
>
>I have not been fully convinced by this approach yet. Taking a general
>chain definition as follows,
>
><chain>
>  <command class="C1"/>
>  <command class="C2"/>
>  <command class="C3"/>
>  ...
>  <command class="C19"/>
>  <command class="C20"/>
></chain>
>
>If I want to add a new command C before C19, I'll have to figure out
>who set up a state before C19, even on one does it.
>
Not true.  You don't care who set up state .. you care only if your 
newly inserted command is relevant or not, since it will always be executed.

> Also,
>I'll have to figure out where the state is located if any and see if the new
>command C honor that state or not (command coupling problem).
>  
>
Why should you expect any *other* command to decide whether *your* new 
command is relevant or not.  That's *your* problem.

>Furthermore, assume the command C3 set up a state, but we could
>see any commands between C3 and C19 could set up a second one
>or third one. Where the states are stored systematically is another
>question (state storage problem).
>  
>
"State is in the eyes of the beholder" :-).  If you can't decide for 
yourself when your newly inserted command is relevant, then by 
definition you are at fault, because there is no way for your command 
component to be independently testable and reusable.

>I could be convinced if I see a possible mechanism that deals with
>the command coupling problem and state storage problem.
>  
>
Jing, it is sounding more and more like what you want is a scripting 
control flow language expressed in XML.  That is absolutely, totally, 
*not* what commons-chain is about.  Feel free to invent your own package 
for this purpose.  Feel free to popularize it all you want.  You're even 
welcome to say "this is an extension to commons-chain that supports 
branches and labels".  But commons-chain itself is going to stay focused 
on the pure CoR pattern, which has absolutely no notion of branches or 
labels in the fundamental APIs.  Such things, therefore, do not belong 
in the fundamental commons-chain APIs.

I'm not going to bother to respond to any further discussion along this 
line -- as far as I'm concerned, the case for adding branches and labels 
has failed to illustrate that it has any technical merit (for 
commons-chain), and I'm not interested in spending any more time 
discussing it.  What you do in your own projects (open source or not) 
is, of course, totally up to you.

>  
>
>>Craig
>>
>>    
>>
>
>Jing
>  
>
Craig



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


Re: Struts-chain Behavior Discussion

Posted by Jing Zhou <ji...@netspread.com>.
> In the example, the L1 labeled chain is invoked by Class1 if it returns
> false.

Sorry, it should be changed to "if it returns true" (to terminate the
original
chain instance).

Jing


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


Re: Struts-chain Behavior Discussion

Posted by Jing Zhou <ji...@netspread.com>.
----- Original Message ----- 
From: "Craig R. McClanahan" <cr...@apache.org>
To: "Struts Developers List" <st...@jakarta.apache.org>
Sent: Tuesday, October 07, 2003 2:22 PM
Subject: Re: Struts-chain Behavior Discussion


> >
> >You do not need to determine Class4 was always run or not,
> >actually it is determined at runtime. Its definition is included
> >in every labeled chain by default.
> >
> It is absolutely necessary to understand the control flow if you want to
> customize it.  The above would support all of the following flows
> (assuming that no command returns true prematurely):
> * Class1 - Class2 - Class3 - Class4
> * Class1 - Class3 - Class4
> * Class1 - Class2 - Class4
>
> Now, if I want to add a new step that has to occur before Class3, but is
> ONLY executed if Class3 will be executed, how do I do that?  I have to
> change which command gets label L1, which is bad for the same reason
> that "goto" in programming languages is bad.

You could easily assign the label L1 to the new command before Class3
in the chain. A chain definition is normally very very small (5-30 lines)
comparing with programs (up to 8000 or more lines). I do not see any
difficulties to manipulate such a small section. Note that the thing we are
dealing with is a config file, not a program (with a "go to" from line 67 to
line 7598 :-)

>
> >
> >The idea is that you do not have to define a separate chain else where
> >if you could re-use a labeled chain in the current chain definition.
> >You could also ignore  labels if any, just use the chain as is.
> >
> >
> If you're going to (potentially) ignore the labels and branches, why
> have them in the first place?

In the example, the L1 labeled chain is invoked by Class1 if it returns
false. If you do not need the particular L1 labeled chain in the current
chain definition, you could ignore it. But the label could serve as
an entry point for other chains outside the scope to invoke the L1
labeled chain if they find it useful.

>
> Or, to put it differently, conditional behavior should be a feature of
> the Command implementation ("is the world in the correct state for me to
> perform this action?").  If the current state is not correct, it should
> just return false to let the chain continue.  That's why a change based
> on Ted's suggestion:
>
> (1) LookupCommand
> (2) ExceptionCatcher
> (3) SelectLocale
> (4) SelectAction
> (5) CreateActionForm
> (6) PopulateActionForm
> (7) ValidateActionForm (must save state in the Context)
> (NEW) SelectInput [skip if validation succeeded]
> (8) CreateAction [skip if validation failed]
> (9) ExecuteAction [skip if validation failed]
> (10) PerformForward
>
> is actually the cleanest overall approach.  The user should not have to
> even *know* what conditions the commands care about to determine whether
> they are executed.  Thus, you would end up with a clean and simple chain
> definition:
>
> <chain id="request-processor">
>   <command class="LookupCommand"/>
>   <command class="ExceptionCatcher"/>
>   <command class="SelectLocale"/>
>   <command class="SelectAction"/>
>   <command class="CreateActionForm"/>
>   <command class="PopulateActionForm"/>
>   <command class="ValidateActionForm"/>
>   <command class="SelectInput"/>
>   <command class="CreateAction"/>
>   <command class="ExecuteAction"/>
>   <command class="PerformForward"/>
> </chain>
>
> Now, if I want to insert something that always happens before
> ValidateActionForm, I know exactly where it goes.  I don't have to worry
> about whether ValidateActionForm is going to branch or skip, because
> it's not ... SelectInput and friends decide for themselves whether they
> are relevant.
>
> OK, I've convinced myself that this is the right approach :-).  So I'll
> likely be changing struts-chain to this tonight, and adding the
> appropriate mechanisms for ValidateActionForm to pass on the success or
> failure state information.

I have not been fully convinced by this approach yet. Taking a general
chain definition as follows,

<chain>
  <command class="C1"/>
  <command class="C2"/>
  <command class="C3"/>
  ...
  <command class="C19"/>
  <command class="C20"/>
</chain>

If I want to add a new command C before C19, I'll have to figure out
who set up a state before C19, even on one does it. Also,
I'll have to figure out where the state is located if any and see if the new
command C honor that state or not (command coupling problem).

Furthermore, assume the command C3 set up a state, but we could
see any commands between C3 and C19 could set up a second one
or third one. Where the states are stored systematically is another
question (state storage problem).

I could be convinced if I see a possible mechanism that deals with
the command coupling problem and state storage problem.

>
> Craig
>

Jing



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


Re: Struts-chain Behavior Discussion

Posted by "Craig R. McClanahan" <cr...@apache.org>.
Jing Zhou wrote:

>>It's not so much about "complexity" as it is readability.
>>    
>>
>
>The "complexity" in my message refers to the verboseness of the
>chain-config.xml file. What I am looking for is a possible
>simpler syntax to do the job.
>
>  
>
>>If I care what Process Action is then I can see the detail.  Goto's
>>were deemed dangerous because of the behavior that they hide.  They
>>obfuscate the flow of the code.  It's not really any different here
>>either.
>>
>>    
>>
>>>><command jumpLabel="L1" className="Class1" />
>>>><command jumpLabel="L2" className="Class2" />
>>>><command label="L1" className="Class3" />
>>>><command label="L2" className="Class4" />
>>>>        
>>>>
>>I had a longer response prepared to your other post, but decided it
>>was too wordy. :)  One example where the obfuscation comes in is that
>>I had to look at it for a bit before determining that Class4 was 
>>always run.  If a few more commands are thrown in, it really gets
>>confusing.
>>    
>>
>
>You do not need to determine Class4 was always run or not,
>actually it is determined at runtime. Its definition is included 
>in every labeled chain by default.
>
It is absolutely necessary to understand the control flow if you want to 
customize it.  The above would support all of the following flows 
(assuming that no command returns true prematurely):
* Class1 - Class2 - Class3 - Class4
* Class1 - Class3 - Class4
* Class1 - Class2 - Class4

Now, if I want to add a new step that has to occur before Class3, but is 
ONLY executed if Class3 will be executed, how do I do that?  I have to 
change which command gets label L1, which is bad for the same reason 
that "goto" in programming languages is bad.

>
>The idea is that you do not have to define a separate chain else where
>if you could re-use a labeled chain in the current chain definition.
>You could also ignore  labels if any, just use the chain as is.
>  
>
If you're going to (potentially) ignore the labels and branches, why 
have them in the first place?

Or, to put it differently, conditional behavior should be a feature of 
the Command implementation ("is the world in the correct state for me to 
perform this action?").  If the current state is not correct, it should 
just return false to let the chain continue.  That's why a change based 
on Ted's suggestion:

(1) LookupCommand
(2) ExceptionCatcher
(3) SelectLocale
(4) SelectAction
(5) CreateActionForm
(6) PopulateActionForm
(7) ValidateActionForm (must save state in the Context)
(NEW) SelectInput [skip if validation succeeded]
(8) CreateAction [skip if validation failed]
(9) ExecuteAction [skip if validation failed]
(10) PerformForward

is actually the cleanest overall approach.  The user should not have to 
even *know* what conditions the commands care about to determine whether 
they are executed.  Thus, you would end up with a clean and simple chain 
definition:

<chain id="request-processor">
  <command class="LookupCommand"/>
  <command class="ExceptionCatcher"/>
  <command class="SelectLocale"/>
  <command class="SelectAction"/>
  <command class="CreateActionForm"/>
  <command class="PopulateActionForm"/>
  <command class="ValidateActionForm"/>
  <command class="SelectInput"/>
  <command class="CreateAction"/>
  <command class="ExecuteAction"/>
  <command class="PerformForward"/>
</chain>

Now, if I want to insert something that always happens before 
ValidateActionForm, I know exactly where it goes.  I don't have to worry 
about whether ValidateActionForm is going to branch or skip, because 
it's not ... SelectInput and friends decide for themselves whether they 
are relevant.

OK, I've convinced myself that this is the right approach :-).  So I'll 
likely be changing struts-chain to this tonight, and adding the 
appropriate mechanisms for ValidateActionForm to pass on the success or 
failure state information.

>  
>
>>-Paul
>>
>>    
>>
>
>Jing
>  
>
Craig



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


Re: Struts-chain Behavior Discussion

Posted by Jing Zhou <ji...@netspread.com>.
> It's not so much about "complexity" as it is readability.

The "complexity" in my message refers to the verboseness of the
chain-config.xml file. What I am looking for is a possible
simpler syntax to do the job.

> If I care what Process Action is then I can see the detail.  Goto's
> were deemed dangerous because of the behavior that they hide.  They
> obfuscate the flow of the code.  It's not really any different here
> either.
> 
> > > <command jumpLabel="L1" className="Class1" />
> > > <command jumpLabel="L2" className="Class2" />
> > > <command label="L1" className="Class3" />
> > > <command label="L2" className="Class4" />
> 
> I had a longer response prepared to your other post, but decided it
> was too wordy. :)  One example where the obfuscation comes in is that
> I had to look at it for a bit before determining that Class4 was 
> always run.  If a few more commands are thrown in, it really gets
> confusing.

You do not need to determine Class4 was always run or not,
actually it is determined at runtime. Its definition is included 
in every labeled chain by default.

The idea is that you do not have to define a separate chain else where
if you could re-use a labeled chain in the current chain definition.
You could also ignore  labels if any, just use the chain as is.

> 
> -Paul
> 

Jing


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


Re: Struts-chain Behavior Discussion

Posted by Paul Speed <ps...@progeeks.com>.

Jing Zhou wrote:
> 
> ----- Original Message -----
> From: "Paul Speed" <ps...@progeeks.com>
> To: "Struts Developers List" <st...@jakarta.apache.org>
> Sent: Monday, October 06, 2003 5:58 PM
> Subject: Re: Struts-chain Behavior Discussion
> 
> >
> >
> > Jing Zhou wrote:
> > >
> > > ----- Original Message -----
> > > From: "Paul Speed" <ps...@progeeks.com>
> > > To: "Struts Developers List" <st...@jakarta.apache.org>
> > > Sent: Monday, October 06, 2003 3:40 AM
> > > Subject: Re: Struts-chain Behavior Discussion
> > >
> > > >
> > > > (1) LookupCommand
> > > > (2) ExceptionCatcher
> > > > (3) SelectLocale
> > > > (4) Process Action
> > > >     (a) SelectAction
> > > >     (b) CreateActionForm
> > > >     (c) PopulateActionForm
> > > >     (d) ValidateActionForm
> > >
> > > If validations fail in (d), the (e) and (f) are not necessary.
> >
> > Right, but then it can just stop that particular chain.  I was under
> > the impression that a chain can be aborted.  If validation fails
> > then the "Process Action" chain could abort and the main chain would
> > continue on to "PerformForward".
> >
> > Incorporating Craig's comments about "SelectInput" on validation
> > failure are left as an exercise for the reader. ;)
> 
> I see what you mean. But the complexity is roughly the same
> as or more than the original one in chain-config.xml. What I am
> looking for is a simpler syntax to do the same thing without explicitly
> defining possible nested chains. See my previous message, an example
> is given.

It's not so much about "complexity" as it is readability.  In the above
example, the main steps are pretty clear:

(1) LookupCommand
(2) ExceptionCatcher
(3) SelectLocale
(4) Process Action
(5) PerformForward

(For clarity, I might even lump the first three into their own chain.)

If I care what Process Action is then I can see the detail.  Goto's
were deemed dangerous because of the behavior that they hide.  They
obfuscate the flow of the code.  It's not really any different here
either.

> > <command jumpLabel="L1" className="Class1" />
> > <command jumpLabel="L2" className="Class2" />
> > <command label="L1" className="Class3" />
> > <command label="L2" className="Class4" />

I had a longer response prepared to your other post, but decided it
was too wordy. :)  One example where the obfuscation comes in is that
I had to look at it for a bit before determining that Class4 was 
always run.  If a few more commands are thrown in, it really gets
confusing.

-Paul

> 
> >
> > -Paul
> 
> Jing
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: struts-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: struts-dev-help@jakarta.apache.org

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


Re: Struts-chain Behavior Discussion

Posted by Jing Zhou <ji...@netspread.com>.
----- Original Message ----- 
From: "Paul Speed" <ps...@progeeks.com>
To: "Struts Developers List" <st...@jakarta.apache.org>
Sent: Monday, October 06, 2003 5:58 PM
Subject: Re: Struts-chain Behavior Discussion


> 
> 
> Jing Zhou wrote:
> > 
> > ----- Original Message -----
> > From: "Paul Speed" <ps...@progeeks.com>
> > To: "Struts Developers List" <st...@jakarta.apache.org>
> > Sent: Monday, October 06, 2003 3:40 AM
> > Subject: Re: Struts-chain Behavior Discussion
> > 
> > >
> > > (1) LookupCommand
> > > (2) ExceptionCatcher
> > > (3) SelectLocale
> > > (4) Process Action
> > >     (a) SelectAction
> > >     (b) CreateActionForm
> > >     (c) PopulateActionForm
> > >     (d) ValidateActionForm
> > 
> > If validations fail in (d), the (e) and (f) are not necessary.
> 
> Right, but then it can just stop that particular chain.  I was under
> the impression that a chain can be aborted.  If validation fails
> then the "Process Action" chain could abort and the main chain would
> continue on to "PerformForward".
> 
> Incorporating Craig's comments about "SelectInput" on validation 
> failure are left as an exercise for the reader. ;)

I see what you mean. But the complexity is roughly the same
as or more than the original one in chain-config.xml. What I am 
looking for is a simpler syntax to do the same thing without explicitly
defining possible nested chains. See my previous message, an example 
is given.

> 
> -Paul

Jing


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


Re: Struts-chain Behavior Discussion

Posted by Paul Speed <ps...@progeeks.com>.

Jing Zhou wrote:
> 
> ----- Original Message -----
> From: "Paul Speed" <ps...@progeeks.com>
> To: "Struts Developers List" <st...@jakarta.apache.org>
> Sent: Monday, October 06, 2003 3:40 AM
> Subject: Re: Struts-chain Behavior Discussion
> 
> >
> > (1) LookupCommand
> > (2) ExceptionCatcher
> > (3) SelectLocale
> > (4) Process Action
> >     (a) SelectAction
> >     (b) CreateActionForm
> >     (c) PopulateActionForm
> >     (d) ValidateActionForm
> 
> If validations fail in (d), the (e) and (f) are not necessary.

Right, but then it can just stop that particular chain.  I was under
the impression that a chain can be aborted.  If validation fails
then the "Process Action" chain could abort and the main chain would
continue on to "PerformForward".

Incorporating Craig's comments about "SelectInput" on validation 
failure are left as an exercise for the reader. ;)

-Paul

> 
> >     (e) CreateAction
> >     (f) ExecuteAction
> > (8) PerformForward
> >
> > >
> > > -Paul
> > >
> 
> Jing
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: struts-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: struts-dev-help@jakarta.apache.org

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


Re: Struts-chain Behavior Discussion

Posted by Jing Zhou <ji...@netspread.com>.
----- Original Message ----- 
From: "Paul Speed" <ps...@progeeks.com>
To: "Struts Developers List" <st...@jakarta.apache.org>
Sent: Monday, October 06, 2003 3:40 AM
Subject: Re: Struts-chain Behavior Discussion


> 
> (1) LookupCommand
> (2) ExceptionCatcher
> (3) SelectLocale
> (4) Process Action
>     (a) SelectAction
>     (b) CreateActionForm
>     (c) PopulateActionForm
>     (d) ValidateActionForm

If validations fail in (d), the (e) and (f) are not necessary.

>     (e) CreateAction
>     (f) ExecuteAction
> (8) PerformForward
> 
> > 
> > -Paul
> > 

Jing

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


Re: Struts-chain Behavior Discussion

Posted by Paul Speed <ps...@progeeks.com>.

Paul Speed wrote:
> 
> I haven't looked at the implementation yet (I intend to when I have
> more than 2 seconds free) but I have been lurking in this
> discussion.
> 
> It seems to me that if a command could nest a chain then all things
> are possible.  In fact, you wouldn't even need the "jump to last
> command" logic since that step would be part of the master chain.
> 
> Craig's example might then be like:
> (1) LookupCommand
> (2) ExceptionCatcher
> (3) SelectLocale
> (4) SelectAction
> (5) Process Form
>     (a) CreateActionForm
>     (b) PopulateActionForm
>     (c) ValidateActionForm
> (6) CreateAction
> (7) ExecuteAction
> (8) PerformForward

Yah, except I screwed it up.  It's way too late.

(1) LookupCommand
(2) ExceptionCatcher
(3) SelectLocale
(4) Process Action
    (a) SelectAction
    (b) CreateActionForm
    (c) PopulateActionForm
    (d) ValidateActionForm
    (e) CreateAction
    (f) ExecuteAction
(8) PerformForward

> 
> I don't know how easy it would be to run a chain from a command, so
> it may not be feasible.  From a processing perspective, it seems
> clearer to me.
> 
> -Paul
> 
> Jing Zhou wrote:
> >
> > ----- Original Message -----
> > From: "Craig R. McClanahan" <cr...@apache.org>
> > To: "Struts Developers List" <st...@jakarta.apache.org>
> > Sent: Saturday, October 04, 2003 1:02 PM
> > Subject: Re: Struts-chain Behavior Discussion
> >
> > >
> > > They could indeed be made part of the chain, and "checking the current
> > > state to see if it's appropriate for me to do anything" is certainly
> > > more in the spirit of the original CoR pattern.  However, I worry a
> > > little that creating the need for that state information increases
> > > coupling between commands, and therefore increases the complexity of
> > > reusing commands in alternative chains.
> >
> > Exactly. The index-based jumping creates the need for a command to
> > recognize a fixed position to jump to. That is why I said
> > they have a similar problem - coupling between commands. They
> > have to either honor a state/flag or a fixed position. And such coupling
> > can be easily destroyed by adding a command in between without
> > recognizing the state/flag or changing the target position.
> >
> > >
> > > In the real-life use case we actually have in the CVS repository (the
> > > one in struts-chain, which actually does work :-), the case in question
> > > was to deal with the fact that the Struts request processing lifecycle
> > > has a branch in it, based on whether or not validation succeeds.  The
> > > basic flow goes like this (using the class name of the command
> > > implementation class, and presuming we're all pretty familiar with the
> > > corresponding RequestProcessor behavior):
> > >
> > > (1) LookupCommand (analogous to the processPreprocess() hook)
> > > (2) ExceptionCatcher (no direct analog - used to implement exception
> > > mapping behavior)
> > > (3) SelectLocale
> > > (4) SelectAction
> > > (5) CreateActionForm
> > > (6) PopulateActionForm
> > > (7) ValidateActionForm
> > > (8) CreateAction
> > > (9) ExecuteAction
> > > (10) PerformForward
> > >
> > > The conditional behavior happens in Step (7) -- if validation fails, an
> > > alternative path is desired:
> > > (7a) SelectInput (uses the "input" attribute on the <action>)
> > > (7b) PerformForward
> > >
> > > At the moment, this is implemented as a branch, to a separate chain that
> > > the author of ValidateActionForm need not even know the name of at
> > > design time (it's a configuration property).  If ValidateActionForm
> > > detects a failure, it looks up an alternate chain in the Catalog,
> > > executes this chain, and then returns true (so that steps 8-10 of the
> > > original chain are never executed).  Note that step (10) in the original
> > > chain and step (7b) in the alternate chain share a single Command
> > > implementation instance, because Struts ends up doing the same thing
> > > either way (RequestDispatcher.forward() or redirect based on what
> > > ActionForward it is passed).  Nothing had to be coded twice.
> > >
> >
> > My question is whether or not we could find a simpler
> > syntax in the chain-config.xml and implement "jump behavior".
> > This is because we could have a lot of "jump to the last command"
> > or "jump to the second to last command", etc.
> >
> > It is very easy to relate "branch behavior" and "jump behavior" to
> > a rule engine or workflow engine, so people might get me wrong
> > in the early reactions.
> >
> > Although we use the term "branch behavior" and "jump behavior"
> > in a chain, we should not see the "if" and "go to" statements in the
> > chain-config.xml file. So a chain is still a fully connected chain
> > (no skipping by definition).
> >
> > The "if" statement is simulated by commands which
> > provide "branch behavior" by terminating the current chain and
> > invoking a nested chain.
> >
> > Could we simulate the "go to" statement without breaking the chain?
> > Note that the chain's execution path should be remained connected
> > because we need to do post processing in the reversed order.
> >
> > The answer, I deeply believe, is yes. We know that index-based
> > jumping is flawed, so we should use label-based jumping. When
> > a command is added to a chain, an optional label could be
> > specified which must be unique within the chain.
> >
> > For example,
> > <chains>
> >   <chain name="servlet-standard">
> >       <command className="o.a.s.c.s.ValidationFormAction"
> >                         jumpLabel="last" />
> >       ....
> >       <!-- the label "last" is specified in the next command -->
> >      <command label="last"
> >                        className="o.a.s.c.s.PerformForward" />
> >   </chain>
> > </chains>
> >
> > Now, in the ValidationFormAction class, we almost do the same
> > thing as before except in two statements:
> >
> > >     ActionErrors errors = validate(context, actionConfig, actionForm);
> > >
> > >     // If there were no errors, proceed normally
> > >     if ((errors == null) || (errors.isEmpty()) {
> > >         return (false); // Proceed with the main chain
> > >     }
> > >
> > >     // Execute the specified validation failure command
> > >     try {
> > >         Catalog catalog = (Catalog)
> > >           context.get(getCatalogKey());
> >
> >            // we get the main chain again
> >            Command command = catalog.getCommand("servlet-standard");
> >            // execute the main chain starting with the given label
> >           ((Chain)command).execute(context, getJumpLabel());
> >
> > >     } catch (Exception e) {
> > >         ... deal with exception ...
> > >     }
> > >     return (true); // Terminate the main chain
> > >
> > > Craig
> > >
> >
> > Here, we introduce a concept of implicit chains. Whenever
> > you add a command with its label in a chain, an implicit
> > chain is defined starting from that command to the end of the
> > chain. The Chain.execute(Context ctx, String label) will
> > execute the chain from the labeled command.
> >
> > So, the "go to" statement is actually simulated by a nested
> > chain which is implicitly defined in the main chain.
> >
> > Obviously, we do not have to require each command to
> > honor a state/flag, and the fixed index problem is also
> > solved. Now, looped commands can be specified
> > as follows. (Note that you can not simulate the looped
> > commands using "branch behavior").
> >
> > <chains>
> >   <chain name="demo">
> >
> >       <command className="A" />
> >       <command label="start" className="B" />
> >       // ... other looped commands
> >
> >       <command jumpLabel="start" className="C" />
> >
> >   </chain>
> > </chains>
> >
> > This way also saves a lot of repeatedly defined
> > commands/chains in the chain-config.xml file.
> > What I am asking is still a Chain, but with additional
> > capabilities and more concise syntaxes. Although its
> > syntaxes looks like a "jump", its implementation
> > never jumps. (It may not be necessary to add new
> > execute method if we could put label into Context
> > somewhere, so API changes are very limited).
> >
> > Any ideas or comments on the algorithm? Are there
> > any technique flaws? If anywhere is not clear or
> > could be improved, please point it out.
> >
> > Jing
> > Netspread Carrier
> > http://www.netspread.com
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: struts-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: struts-dev-help@jakarta.apache.org
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: struts-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: struts-dev-help@jakarta.apache.org

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


Re: Struts-chain Behavior Discussion

Posted by "Craig R. McClanahan" <cr...@apache.org>.
Ted Husted wrote:

> Craig R. McClanahan wrote:
>
>> * The way it's currently implemented -- ValidateActionForm
>>  conditionally branches to a separate chain on validation
>>  failure ("servlet-validation-failure" in the current config file),
>>  and [returns true to] abandon the remainder of the original chain.
>
>
> The phrase "conditionally *nests* a separate chain" might be more 
> accurate. Branch implies the Command loses control, which is not the 
> case.
>
> dictionary.com / Computer Science
>
> branch - To relinquish control to another set of instructions or 
> another routine as a result of the presence of a branch.

Nitpicking, I know, but ...

 From the perspective of the original chain, this is exactly what 
happens -- the original chain relinquishes control, and the remainder of 
the original steps are never actually executed (because 
ValidateActionForm returns true when the alternate chain is finished).

>
> nest - A set of data contained sequentially within another.

You might recall that the original approach to this functionality really 
did nest -- ValidateActionForm was a Chain that conditionally executed 
it's nested commands instead of continuing.  As was pointed out then, 
this was sort of a corruption of the CoR pattern, because the remainder 
of the original chain is *still* abandoned (because the last command in 
the nested chain returns true) -- but you can't tell that from looking 
at a structural diagram of the commands.

It's perfectly reasonable to use nested chains for composing complex 
things out of simple things -- that's why a Chain is-a Command.  But the 
original feedback was correct -- this shouldn't be used as a structure 
for conditional processing; explicity branching is better.

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




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


Re: Struts-chain Behavior Discussion

Posted by Ted Husted <hu...@apache.org>.
Craig R. McClanahan wrote:
> * The way it's currently implemented -- ValidateActionForm
>  conditionally branches to a separate chain on validation
>  failure ("servlet-validation-failure" in the current config file),
>  and [returns true to] abandon the remainder of the original chain.

The phrase "conditionally *nests* a separate chain" might be more 
accurate. Branch implies the Command loses control, which is not the case.

dictionary.com / Computer Science

branch - To relinquish control to another set of instructions or another 
routine as a result of the presence of a branch.

nest - A set of data contained sequentially within another.

-Ted.



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


Re: Struts-chain Behavior Discussion

Posted by "Craig R. McClanahan" <cr...@apache.org>.
Paul Speed wrote:

>I haven't looked at the implementation yet (I intend to when I have
>more than 2 seconds free) but I have been lurking in this 
>discussion.
>
>It seems to me that if a command could nest a chain then all things
>are possible.  In fact, you wouldn't even need the "jump to last
>command" logic since that step would be part of the master chain.
>
>Craig's example might then be like:
>(1) LookupCommand 
>(2) ExceptionCatcher 
>(3) SelectLocale
>(4) SelectAction
>(5) Process Form
>    (a) CreateActionForm
>    (b) PopulateActionForm
>    (c) ValidateActionForm
>(6) CreateAction
>(7) ExecuteAction
>(8) PerformForward
>  
>
This isn't what you really want ... if validation fails you need:
    SelectInput
    PerformForward

whereas if validation succeeds you want:
    CreateAction
    ExecuteAction
    PerformForward

Note that the last step is the same in either case.

This can be accomplished in two different ways with commons-chain "as is":

* The way it's currently implemented -- ValidateActionForm
  conditionally branches to a separate chain on validation
  failure ("servlet-validation-failure" in the current config file),
  and abandon the remainder of the original chain.

* A change to add SelectInput into the standard chain after
  ValidateActionForm, have ValidateActionForm save the success
  or failure of validation in the Context, have SelectInput return
  false if validation succeeded, have CreateAction return false if
  validation failed, and have ExecuteAction return false if validation
  failed.

In either case, no changes to how commons-chain works are required.

>
>I don't know how easy it would be to run a chain from a command, so
>it may not be feasible.  From a processing perspective, it seems
>clearer to me.
>  
>
Except that it doesn't do the right thing in case of validation failures 
(i.e. look at the "input" parameter).

>-Paul
>
Craig

>
>Jing Zhou wrote:
>  
>
>>----- Original Message -----
>>From: "Craig R. McClanahan" <cr...@apache.org>
>>To: "Struts Developers List" <st...@jakarta.apache.org>
>>Sent: Saturday, October 04, 2003 1:02 PM
>>Subject: Re: Struts-chain Behavior Discussion
>>
>>    
>>
>>>They could indeed be made part of the chain, and "checking the current
>>>state to see if it's appropriate for me to do anything" is certainly
>>>more in the spirit of the original CoR pattern.  However, I worry a
>>>little that creating the need for that state information increases
>>>coupling between commands, and therefore increases the complexity of
>>>reusing commands in alternative chains.
>>>      
>>>
>>Exactly. The index-based jumping creates the need for a command to
>>recognize a fixed position to jump to. That is why I said
>>they have a similar problem - coupling between commands. They
>>have to either honor a state/flag or a fixed position. And such coupling
>>can be easily destroyed by adding a command in between without
>>recognizing the state/flag or changing the target position.
>>
>>    
>>
>>>In the real-life use case we actually have in the CVS repository (the
>>>one in struts-chain, which actually does work :-), the case in question
>>>was to deal with the fact that the Struts request processing lifecycle
>>>has a branch in it, based on whether or not validation succeeds.  The
>>>basic flow goes like this (using the class name of the command
>>>implementation class, and presuming we're all pretty familiar with the
>>>corresponding RequestProcessor behavior):
>>>
>>>(1) LookupCommand (analogous to the processPreprocess() hook)
>>>(2) ExceptionCatcher (no direct analog - used to implement exception
>>>mapping behavior)
>>>(3) SelectLocale
>>>(4) SelectAction
>>>(5) CreateActionForm
>>>(6) PopulateActionForm
>>>(7) ValidateActionForm
>>>(8) CreateAction
>>>(9) ExecuteAction
>>>(10) PerformForward
>>>
>>>The conditional behavior happens in Step (7) -- if validation fails, an
>>>alternative path is desired:
>>>(7a) SelectInput (uses the "input" attribute on the <action>)
>>>(7b) PerformForward
>>>
>>>At the moment, this is implemented as a branch, to a separate chain that
>>>the author of ValidateActionForm need not even know the name of at
>>>design time (it's a configuration property).  If ValidateActionForm
>>>detects a failure, it looks up an alternate chain in the Catalog,
>>>executes this chain, and then returns true (so that steps 8-10 of the
>>>original chain are never executed).  Note that step (10) in the original
>>>chain and step (7b) in the alternate chain share a single Command
>>>implementation instance, because Struts ends up doing the same thing
>>>either way (RequestDispatcher.forward() or redirect based on what
>>>ActionForward it is passed).  Nothing had to be coded twice.
>>>
>>>      
>>>
>>My question is whether or not we could find a simpler
>>syntax in the chain-config.xml and implement "jump behavior".
>>This is because we could have a lot of "jump to the last command"
>>or "jump to the second to last command", etc.
>>
>>It is very easy to relate "branch behavior" and "jump behavior" to
>>a rule engine or workflow engine, so people might get me wrong
>>in the early reactions.
>>
>>Although we use the term "branch behavior" and "jump behavior"
>>in a chain, we should not see the "if" and "go to" statements in the
>>chain-config.xml file. So a chain is still a fully connected chain
>>(no skipping by definition).
>>
>>The "if" statement is simulated by commands which
>>provide "branch behavior" by terminating the current chain and
>>invoking a nested chain.
>>
>>Could we simulate the "go to" statement without breaking the chain?
>>Note that the chain's execution path should be remained connected
>>because we need to do post processing in the reversed order.
>>
>>The answer, I deeply believe, is yes. We know that index-based
>>jumping is flawed, so we should use label-based jumping. When
>>a command is added to a chain, an optional label could be
>>specified which must be unique within the chain.
>>
>>For example,
>><chains>
>>  <chain name="servlet-standard">
>>      <command className="o.a.s.c.s.ValidationFormAction"
>>                        jumpLabel="last" />
>>      ....
>>      <!-- the label "last" is specified in the next command -->
>>     <command label="last"
>>                       className="o.a.s.c.s.PerformForward" />
>>  </chain>
>></chains>
>>
>>Now, in the ValidationFormAction class, we almost do the same
>>thing as before except in two statements:
>>
>>    
>>
>>>    ActionErrors errors = validate(context, actionConfig, actionForm);
>>>
>>>    // If there were no errors, proceed normally
>>>    if ((errors == null) || (errors.isEmpty()) {
>>>        return (false); // Proceed with the main chain
>>>    }
>>>
>>>    // Execute the specified validation failure command
>>>    try {
>>>        Catalog catalog = (Catalog)
>>>          context.get(getCatalogKey());
>>>      
>>>
>>           // we get the main chain again
>>           Command command = catalog.getCommand("servlet-standard");
>>           // execute the main chain starting with the given label
>>          ((Chain)command).execute(context, getJumpLabel());
>>
>>    
>>
>>>    } catch (Exception e) {
>>>        ... deal with exception ...
>>>    }
>>>    return (true); // Terminate the main chain
>>>
>>>Craig
>>>
>>>      
>>>
>>Here, we introduce a concept of implicit chains. Whenever
>>you add a command with its label in a chain, an implicit
>>chain is defined starting from that command to the end of the
>>chain. The Chain.execute(Context ctx, String label) will
>>execute the chain from the labeled command.
>>
>>So, the "go to" statement is actually simulated by a nested
>>chain which is implicitly defined in the main chain.
>>
>>Obviously, we do not have to require each command to
>>honor a state/flag, and the fixed index problem is also
>>solved. Now, looped commands can be specified
>>as follows. (Note that you can not simulate the looped
>>commands using "branch behavior").
>>
>><chains>
>>  <chain name="demo">
>>
>>      <command className="A" />
>>      <command label="start" className="B" />
>>      // ... other looped commands
>>
>>      <command jumpLabel="start" className="C" />
>>
>>  </chain>
>></chains>
>>
>>This way also saves a lot of repeatedly defined
>>commands/chains in the chain-config.xml file.
>>What I am asking is still a Chain, but with additional
>>capabilities and more concise syntaxes. Although its
>>syntaxes looks like a "jump", its implementation
>>never jumps. (It may not be necessary to add new
>>execute method if we could put label into Context
>>somewhere, so API changes are very limited).
>>
>>Any ideas or comments on the algorithm? Are there
>>any technique flaws? If anywhere is not clear or
>>could be improved, please point it out.
>>
>>Jing
>>Netspread Carrier
>>http://www.netspread.com
>>
>>---------------------------------------------------------------------
>>To unsubscribe, e-mail: struts-dev-unsubscribe@jakarta.apache.org
>>For additional commands, e-mail: struts-dev-help@jakarta.apache.org
>>    
>>
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: struts-dev-unsubscribe@jakarta.apache.org
>For additional commands, e-mail: struts-dev-help@jakarta.apache.org
>  
>



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


Re: Struts-chain Behavior Discussion

Posted by "Craig R. McClanahan" <cr...@apache.org>.
Paul Speed wrote:

>I haven't looked at the implementation yet (I intend to when I have
>more than 2 seconds free) but I have been lurking in this 
>discussion.
>
>It seems to me that if a command could nest a chain then all things
>are possible.  In fact, you wouldn't even need the "jump to last
>command" logic since that step would be part of the master chain.
>
>Craig's example might then be like:
>(1) LookupCommand 
>(2) ExceptionCatcher 
>(3) SelectLocale
>(4) SelectAction
>(5) Process Form
>    (a) CreateActionForm
>    (b) PopulateActionForm
>    (c) ValidateActionForm
>(6) CreateAction
>(7) ExecuteAction
>(8) PerformForward
>
>
>I don't know how easy it would be to run a chain from a command, so
>it may not be feasible.  From a processing perspective, it seems
>clearer to me.
>  
>
Running a command from a chain is trivial.  In fact, that's what the 
ValidateActionForm code (quoted below) already does.  In this case, it's 
done for conditional behavior, but that is not required.  You can 
actually nest chains inside other chains (remember that Chain *extends* 
Command) for arbitrarily complex straight through processing flows.

>-Paul
>  
>
Craig

>Jing Zhou wrote:
>  
>
>>----- Original Message -----
>>From: "Craig R. McClanahan" <cr...@apache.org>
>>To: "Struts Developers List" <st...@jakarta.apache.org>
>>Sent: Saturday, October 04, 2003 1:02 PM
>>Subject: Re: Struts-chain Behavior Discussion
>>
>>    
>>
>>>They could indeed be made part of the chain, and "checking the current
>>>state to see if it's appropriate for me to do anything" is certainly
>>>more in the spirit of the original CoR pattern.  However, I worry a
>>>little that creating the need for that state information increases
>>>coupling between commands, and therefore increases the complexity of
>>>reusing commands in alternative chains.
>>>      
>>>
>>Exactly. The index-based jumping creates the need for a command to
>>recognize a fixed position to jump to. That is why I said
>>they have a similar problem - coupling between commands. They
>>have to either honor a state/flag or a fixed position. And such coupling
>>can be easily destroyed by adding a command in between without
>>recognizing the state/flag or changing the target position.
>>
>>    
>>
>>>In the real-life use case we actually have in the CVS repository (the
>>>one in struts-chain, which actually does work :-), the case in question
>>>was to deal with the fact that the Struts request processing lifecycle
>>>has a branch in it, based on whether or not validation succeeds.  The
>>>basic flow goes like this (using the class name of the command
>>>implementation class, and presuming we're all pretty familiar with the
>>>corresponding RequestProcessor behavior):
>>>
>>>(1) LookupCommand (analogous to the processPreprocess() hook)
>>>(2) ExceptionCatcher (no direct analog - used to implement exception
>>>mapping behavior)
>>>(3) SelectLocale
>>>(4) SelectAction
>>>(5) CreateActionForm
>>>(6) PopulateActionForm
>>>(7) ValidateActionForm
>>>(8) CreateAction
>>>(9) ExecuteAction
>>>(10) PerformForward
>>>
>>>The conditional behavior happens in Step (7) -- if validation fails, an
>>>alternative path is desired:
>>>(7a) SelectInput (uses the "input" attribute on the <action>)
>>>(7b) PerformForward
>>>
>>>At the moment, this is implemented as a branch, to a separate chain that
>>>the author of ValidateActionForm need not even know the name of at
>>>design time (it's a configuration property).  If ValidateActionForm
>>>detects a failure, it looks up an alternate chain in the Catalog,
>>>executes this chain, and then returns true (so that steps 8-10 of the
>>>original chain are never executed).  Note that step (10) in the original
>>>chain and step (7b) in the alternate chain share a single Command
>>>implementation instance, because Struts ends up doing the same thing
>>>either way (RequestDispatcher.forward() or redirect based on what
>>>ActionForward it is passed).  Nothing had to be coded twice.
>>>
>>>      
>>>
>>My question is whether or not we could find a simpler
>>syntax in the chain-config.xml and implement "jump behavior".
>>This is because we could have a lot of "jump to the last command"
>>or "jump to the second to last command", etc.
>>
>>It is very easy to relate "branch behavior" and "jump behavior" to
>>a rule engine or workflow engine, so people might get me wrong
>>in the early reactions.
>>
>>Although we use the term "branch behavior" and "jump behavior"
>>in a chain, we should not see the "if" and "go to" statements in the
>>chain-config.xml file. So a chain is still a fully connected chain
>>(no skipping by definition).
>>
>>The "if" statement is simulated by commands which
>>provide "branch behavior" by terminating the current chain and
>>invoking a nested chain.
>>
>>Could we simulate the "go to" statement without breaking the chain?
>>Note that the chain's execution path should be remained connected
>>because we need to do post processing in the reversed order.
>>
>>The answer, I deeply believe, is yes. We know that index-based
>>jumping is flawed, so we should use label-based jumping. When
>>a command is added to a chain, an optional label could be
>>specified which must be unique within the chain.
>>
>>For example,
>><chains>
>>  <chain name="servlet-standard">
>>      <command className="o.a.s.c.s.ValidationFormAction"
>>                        jumpLabel="last" />
>>      ....
>>      <!-- the label "last" is specified in the next command -->
>>     <command label="last"
>>                       className="o.a.s.c.s.PerformForward" />
>>  </chain>
>></chains>
>>
>>Now, in the ValidationFormAction class, we almost do the same
>>thing as before except in two statements:
>>
>>    
>>
>>>    ActionErrors errors = validate(context, actionConfig, actionForm);
>>>
>>>    // If there were no errors, proceed normally
>>>    if ((errors == null) || (errors.isEmpty()) {
>>>        return (false); // Proceed with the main chain
>>>    }
>>>
>>>    // Execute the specified validation failure command
>>>    try {
>>>        Catalog catalog = (Catalog)
>>>          context.get(getCatalogKey());
>>>      
>>>
>>           // we get the main chain again
>>           Command command = catalog.getCommand("servlet-standard");
>>           // execute the main chain starting with the given label
>>          ((Chain)command).execute(context, getJumpLabel());
>>
>>    
>>
>>>    } catch (Exception e) {
>>>        ... deal with exception ...
>>>    }
>>>    return (true); // Terminate the main chain
>>>
>>>Craig
>>>
>>>      
>>>
>>Here, we introduce a concept of implicit chains. Whenever
>>you add a command with its label in a chain, an implicit
>>chain is defined starting from that command to the end of the
>>chain. The Chain.execute(Context ctx, String label) will
>>execute the chain from the labeled command.
>>
>>So, the "go to" statement is actually simulated by a nested
>>chain which is implicitly defined in the main chain.
>>
>>Obviously, we do not have to require each command to
>>honor a state/flag, and the fixed index problem is also
>>solved. Now, looped commands can be specified
>>as follows. (Note that you can not simulate the looped
>>commands using "branch behavior").
>>
>><chains>
>>  <chain name="demo">
>>
>>      <command className="A" />
>>      <command label="start" className="B" />
>>      // ... other looped commands
>>
>>      <command jumpLabel="start" className="C" />
>>
>>  </chain>
>></chains>
>>
>>This way also saves a lot of repeatedly defined
>>commands/chains in the chain-config.xml file.
>>What I am asking is still a Chain, but with additional
>>capabilities and more concise syntaxes. Although its
>>syntaxes looks like a "jump", its implementation
>>never jumps. (It may not be necessary to add new
>>execute method if we could put label into Context
>>somewhere, so API changes are very limited).
>>
>>Any ideas or comments on the algorithm? Are there
>>any technique flaws? If anywhere is not clear or
>>could be improved, please point it out.
>>
>>Jing
>>Netspread Carrier
>>http://www.netspread.com
>>
>>---------------------------------------------------------------------
>>To unsubscribe, e-mail: struts-dev-unsubscribe@jakarta.apache.org
>>For additional commands, e-mail: struts-dev-help@jakarta.apache.org
>>    
>>
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: struts-dev-unsubscribe@jakarta.apache.org
>For additional commands, e-mail: struts-dev-help@jakarta.apache.org
>  
>



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


Re: Struts-chain Behavior Discussion

Posted by Paul Speed <ps...@progeeks.com>.
I haven't looked at the implementation yet (I intend to when I have
more than 2 seconds free) but I have been lurking in this 
discussion.

It seems to me that if a command could nest a chain then all things
are possible.  In fact, you wouldn't even need the "jump to last
command" logic since that step would be part of the master chain.

Craig's example might then be like:
(1) LookupCommand 
(2) ExceptionCatcher 
(3) SelectLocale
(4) SelectAction
(5) Process Form
    (a) CreateActionForm
    (b) PopulateActionForm
    (c) ValidateActionForm
(6) CreateAction
(7) ExecuteAction
(8) PerformForward


I don't know how easy it would be to run a chain from a command, so
it may not be feasible.  From a processing perspective, it seems
clearer to me.

-Paul

Jing Zhou wrote:
> 
> ----- Original Message -----
> From: "Craig R. McClanahan" <cr...@apache.org>
> To: "Struts Developers List" <st...@jakarta.apache.org>
> Sent: Saturday, October 04, 2003 1:02 PM
> Subject: Re: Struts-chain Behavior Discussion
> 
> >
> > They could indeed be made part of the chain, and "checking the current
> > state to see if it's appropriate for me to do anything" is certainly
> > more in the spirit of the original CoR pattern.  However, I worry a
> > little that creating the need for that state information increases
> > coupling between commands, and therefore increases the complexity of
> > reusing commands in alternative chains.
> 
> Exactly. The index-based jumping creates the need for a command to
> recognize a fixed position to jump to. That is why I said
> they have a similar problem - coupling between commands. They
> have to either honor a state/flag or a fixed position. And such coupling
> can be easily destroyed by adding a command in between without
> recognizing the state/flag or changing the target position.
> 
> >
> > In the real-life use case we actually have in the CVS repository (the
> > one in struts-chain, which actually does work :-), the case in question
> > was to deal with the fact that the Struts request processing lifecycle
> > has a branch in it, based on whether or not validation succeeds.  The
> > basic flow goes like this (using the class name of the command
> > implementation class, and presuming we're all pretty familiar with the
> > corresponding RequestProcessor behavior):
> >
> > (1) LookupCommand (analogous to the processPreprocess() hook)
> > (2) ExceptionCatcher (no direct analog - used to implement exception
> > mapping behavior)
> > (3) SelectLocale
> > (4) SelectAction
> > (5) CreateActionForm
> > (6) PopulateActionForm
> > (7) ValidateActionForm
> > (8) CreateAction
> > (9) ExecuteAction
> > (10) PerformForward
> >
> > The conditional behavior happens in Step (7) -- if validation fails, an
> > alternative path is desired:
> > (7a) SelectInput (uses the "input" attribute on the <action>)
> > (7b) PerformForward
> >
> > At the moment, this is implemented as a branch, to a separate chain that
> > the author of ValidateActionForm need not even know the name of at
> > design time (it's a configuration property).  If ValidateActionForm
> > detects a failure, it looks up an alternate chain in the Catalog,
> > executes this chain, and then returns true (so that steps 8-10 of the
> > original chain are never executed).  Note that step (10) in the original
> > chain and step (7b) in the alternate chain share a single Command
> > implementation instance, because Struts ends up doing the same thing
> > either way (RequestDispatcher.forward() or redirect based on what
> > ActionForward it is passed).  Nothing had to be coded twice.
> >
> 
> My question is whether or not we could find a simpler
> syntax in the chain-config.xml and implement "jump behavior".
> This is because we could have a lot of "jump to the last command"
> or "jump to the second to last command", etc.
> 
> It is very easy to relate "branch behavior" and "jump behavior" to
> a rule engine or workflow engine, so people might get me wrong
> in the early reactions.
> 
> Although we use the term "branch behavior" and "jump behavior"
> in a chain, we should not see the "if" and "go to" statements in the
> chain-config.xml file. So a chain is still a fully connected chain
> (no skipping by definition).
> 
> The "if" statement is simulated by commands which
> provide "branch behavior" by terminating the current chain and
> invoking a nested chain.
> 
> Could we simulate the "go to" statement without breaking the chain?
> Note that the chain's execution path should be remained connected
> because we need to do post processing in the reversed order.
> 
> The answer, I deeply believe, is yes. We know that index-based
> jumping is flawed, so we should use label-based jumping. When
> a command is added to a chain, an optional label could be
> specified which must be unique within the chain.
> 
> For example,
> <chains>
>   <chain name="servlet-standard">
>       <command className="o.a.s.c.s.ValidationFormAction"
>                         jumpLabel="last" />
>       ....
>       <!-- the label "last" is specified in the next command -->
>      <command label="last"
>                        className="o.a.s.c.s.PerformForward" />
>   </chain>
> </chains>
> 
> Now, in the ValidationFormAction class, we almost do the same
> thing as before except in two statements:
> 
> >     ActionErrors errors = validate(context, actionConfig, actionForm);
> >
> >     // If there were no errors, proceed normally
> >     if ((errors == null) || (errors.isEmpty()) {
> >         return (false); // Proceed with the main chain
> >     }
> >
> >     // Execute the specified validation failure command
> >     try {
> >         Catalog catalog = (Catalog)
> >           context.get(getCatalogKey());
> 
>            // we get the main chain again
>            Command command = catalog.getCommand("servlet-standard");
>            // execute the main chain starting with the given label
>           ((Chain)command).execute(context, getJumpLabel());
> 
> >     } catch (Exception e) {
> >         ... deal with exception ...
> >     }
> >     return (true); // Terminate the main chain
> >
> > Craig
> >
> 
> Here, we introduce a concept of implicit chains. Whenever
> you add a command with its label in a chain, an implicit
> chain is defined starting from that command to the end of the
> chain. The Chain.execute(Context ctx, String label) will
> execute the chain from the labeled command.
> 
> So, the "go to" statement is actually simulated by a nested
> chain which is implicitly defined in the main chain.
> 
> Obviously, we do not have to require each command to
> honor a state/flag, and the fixed index problem is also
> solved. Now, looped commands can be specified
> as follows. (Note that you can not simulate the looped
> commands using "branch behavior").
> 
> <chains>
>   <chain name="demo">
> 
>       <command className="A" />
>       <command label="start" className="B" />
>       // ... other looped commands
> 
>       <command jumpLabel="start" className="C" />
> 
>   </chain>
> </chains>
> 
> This way also saves a lot of repeatedly defined
> commands/chains in the chain-config.xml file.
> What I am asking is still a Chain, but with additional
> capabilities and more concise syntaxes. Although its
> syntaxes looks like a "jump", its implementation
> never jumps. (It may not be necessary to add new
> execute method if we could put label into Context
> somewhere, so API changes are very limited).
> 
> Any ideas or comments on the algorithm? Are there
> any technique flaws? If anywhere is not clear or
> could be improved, please point it out.
> 
> Jing
> Netspread Carrier
> http://www.netspread.com
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: struts-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: struts-dev-help@jakarta.apache.org

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


Re: Struts-chain Behavior Discussion

Posted by Jing Zhou <ji...@netspread.com>.
----- Original Message ----- 
From: "Craig R. McClanahan" <cr...@apache.org>
To: "Struts Developers List" <st...@jakarta.apache.org>
Sent: Saturday, October 04, 2003 1:02 PM
Subject: Re: Struts-chain Behavior Discussion


> 
> They could indeed be made part of the chain, and "checking the current 
> state to see if it's appropriate for me to do anything" is certainly 
> more in the spirit of the original CoR pattern.  However, I worry a 
> little that creating the need for that state information increases 
> coupling between commands, and therefore increases the complexity of 
> reusing commands in alternative chains.

Exactly. The index-based jumping creates the need for a command to
recognize a fixed position to jump to. That is why I said
they have a similar problem - coupling between commands. They
have to either honor a state/flag or a fixed position. And such coupling
can be easily destroyed by adding a command in between without
recognizing the state/flag or changing the target position.

> 
> In the real-life use case we actually have in the CVS repository (the 
> one in struts-chain, which actually does work :-), the case in question 
> was to deal with the fact that the Struts request processing lifecycle 
> has a branch in it, based on whether or not validation succeeds.  The 
> basic flow goes like this (using the class name of the command 
> implementation class, and presuming we're all pretty familiar with the 
> corresponding RequestProcessor behavior):
> 
> (1) LookupCommand (analogous to the processPreprocess() hook)
> (2) ExceptionCatcher (no direct analog - used to implement exception 
> mapping behavior)
> (3) SelectLocale
> (4) SelectAction
> (5) CreateActionForm
> (6) PopulateActionForm
> (7) ValidateActionForm
> (8) CreateAction
> (9) ExecuteAction
> (10) PerformForward
> 
> The conditional behavior happens in Step (7) -- if validation fails, an 
> alternative path is desired:
> (7a) SelectInput (uses the "input" attribute on the <action>)
> (7b) PerformForward
> 
> At the moment, this is implemented as a branch, to a separate chain that 
> the author of ValidateActionForm need not even know the name of at 
> design time (it's a configuration property).  If ValidateActionForm 
> detects a failure, it looks up an alternate chain in the Catalog, 
> executes this chain, and then returns true (so that steps 8-10 of the 
> original chain are never executed).  Note that step (10) in the original 
> chain and step (7b) in the alternate chain share a single Command 
> implementation instance, because Struts ends up doing the same thing 
> either way (RequestDispatcher.forward() or redirect based on what 
> ActionForward it is passed).  Nothing had to be coded twice.
> 

My question is whether or not we could find a simpler
syntax in the chain-config.xml and implement "jump behavior".
This is because we could have a lot of "jump to the last command"
or "jump to the second to last command", etc.

It is very easy to relate "branch behavior" and "jump behavior" to
a rule engine or workflow engine, so people might get me wrong
in the early reactions.

Although we use the term "branch behavior" and "jump behavior"
in a chain, we should not see the "if" and "go to" statements in the
chain-config.xml file. So a chain is still a fully connected chain
(no skipping by definition).

The "if" statement is simulated by commands which
provide "branch behavior" by terminating the current chain and
invoking a nested chain.

Could we simulate the "go to" statement without breaking the chain?
Note that the chain's execution path should be remained connected
because we need to do post processing in the reversed order.

The answer, I deeply believe, is yes. We know that index-based
jumping is flawed, so we should use label-based jumping. When
a command is added to a chain, an optional label could be
specified which must be unique within the chain.

For example,
<chains>
  <chain name="servlet-standard">
      <command className="o.a.s.c.s.ValidationFormAction"
                        jumpLabel="last" />
      ....
      <!-- the label "last" is specified in the next command -->
     <command label="last" 
                       className="o.a.s.c.s.PerformForward" />
  </chain>
</chains>

Now, in the ValidationFormAction class, we almost do the same
thing as before except in two statements:

>     ActionErrors errors = validate(context, actionConfig, actionForm);
>
>     // If there were no errors, proceed normally
>     if ((errors == null) || (errors.isEmpty()) {
>         return (false); // Proceed with the main chain
>     }
>
>     // Execute the specified validation failure command
>     try {
>         Catalog catalog = (Catalog)
>           context.get(getCatalogKey());

           // we get the main chain again
           Command command = catalog.getCommand("servlet-standard");
           // execute the main chain starting with the given label
          ((Chain)command).execute(context, getJumpLabel());

>     } catch (Exception e) {
>         ... deal with exception ...
>     }
>     return (true); // Terminate the main chain
> 
> Craig
> 

Here, we introduce a concept of implicit chains. Whenever
you add a command with its label in a chain, an implicit
chain is defined starting from that command to the end of the
chain. The Chain.execute(Context ctx, String label) will
execute the chain from the labeled command.

So, the "go to" statement is actually simulated by a nested
chain which is implicitly defined in the main chain.

Obviously, we do not have to require each command to
honor a state/flag, and the fixed index problem is also
solved. Now, looped commands can be specified
as follows. (Note that you can not simulate the looped
commands using "branch behavior").

<chains>
  <chain name="demo">

      <command className="A" />
      <command label="start" className="B" />
      // ... other looped commands

      <command jumpLabel="start" className="C" />

  </chain>
</chains>

This way also saves a lot of repeatedly defined
commands/chains in the chain-config.xml file.
What I am asking is still a Chain, but with additional
capabilities and more concise syntaxes. Although its
syntaxes looks like a "jump", its implementation
never jumps. (It may not be necessary to add new
execute method if we could put label into Context
somewhere, so API changes are very limited).

Any ideas or comments on the algorithm? Are there
any technique flaws? If anywhere is not clear or 
could be improved, please point it out.

Jing
Netspread Carrier
http://www.netspread.com


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


Re: Struts-chain Behavior Discussion

Posted by john sessler <jq...@yahoo.com>.
Hello,
 
You may have noticed the posts concerning the request for comments on Action Wrappers which appeared in Aug and a couple of days ago. Action wrappers work with the existing RequestProcessor (1.1) but a much cleaner solution involves a (currently) minor refactoring of the RequestProcessor. I would like to ask that this refactoring proposal be taken into consideration during discussion of and changes to the RequestProcessor.
 
An introduction to Action Wrappers can be found here: http://www.sistemas-jasper.com/indexStrutsActionWrappers.htm. The description of the refactoring can be found in the API documentation of the ActionProcessor class. The refactoring is simple but for brevity I have not cut and paste it here.
 
I believe the action wrappers would be extremely useful to the Struts community, the code exists today and they do not conflict with the idea of action chains. So, once again, I'd like to request consideration for the refacting mentioned.
 
John A. Sessler
 
 

"Craig R. McClanahan" <cr...@apache.org> wrote:
Ted Husted wrote:

> Craig R. McClanahan wrote:
>
>> In terms of the chain implementation of the request processing 
>> lifecycle, this is just an unconditional command in the chain (it's 
>> implemented in o.a.s.c.servlet.PerformForward). No skipping or 
>> stepping is requried. See
>>
>> contrib/struts-chain/src/conf/chain-config.xml
>>
>> for the entire definition. You'll note that it requires no skipping 
>> -- just the conditional behavior on validation failures, which is 
>> modelled as a branch to a separately named command.
>
>
> I wonder if even these conditionals could be made part of the chain. As
> an alternative to branching, the Command could update the state of the
> Context and return false. What is now a conditional Command could be the
> next link the Chain. The "conditional" would check to see if the state
> calls for it to execute, and if so, do its business and return true.

They could indeed be made part of the chain, and "checking the current 
state to see if it's appropriate for me to do anything" is certainly 
more in the spirit of the original CoR pattern. However, I worry a 
little that creating the need for that state information increases 
coupling between commands, and therefore increases the complexity of 
reusing commands in alternative chains.

In the real-life use case we actually have in the CVS repository (the 
one in struts-chain, which actually does work :-), the case in question 
was to deal with the fact that the Struts request processing lifecycle 
has a branch in it, based on whether or not validation succeeds. The 
basic flow goes like this (using the class name of the command 
implementation class, and presuming we're all pretty familiar with the 
corresponding RequestProcessor behavior):

(1) LookupCommand (analogous to the processPreprocess() hook)
(2) ExceptionCatcher (no direct analog - used to implement exception 
mapping behavior)
(3) SelectLocale
(4) SelectAction
(5) CreateActionForm
(6) PopulateActionForm
(7) ValidateActionForm
(8) CreateAction
(9) ExecuteAction
(10) PerformForward

The conditional behavior happens in Step (7) -- if validation fails, an 
alternative path is desired:
(7a) SelectInput (uses the "input" attribute on the )
(7b) PerformForward

At the moment, this is implemented as a branch, to a separate chain that 
the author of ValidateActionForm need not even know the name of at 
design time (it's a configuration property). If ValidateActionForm 
detects a failure, it looks up an alternate chain in the Catalog, 
executes this chain, and then returns true (so that steps 8-10 of the 
original chain are never executed). Note that step (10) in the original 
chain and step (7b) in the alternate chain share a single Command 
implementation instance, because Struts ends up doing the same thing 
either way (RequestDispatcher.forward() or redirect based on what 
ActionForward it is passed). Nothing had to be coded twice.

What would this look like if we merged it into a single chain? Probably 
something like this, with additional state-dependent checking indicated 
in [square brackets]

(1) LookupCommand
(2) ExceptionCatcher
(3) SelectLocale
(4) SelectAction
(5) CreateActionForm
(6) PopulateActionForm
(7) ValidateActionForm (must save state in the Context)
(NEW) SelectInput [skip if validation succeeded]
(8) CreateAction [skip if validation failed]
(9) ExecuteAction [skip if validation failed]
(10) PerformForward

So, implementing this as a single chain would require ValidateActionForm 
to the success/failure state of the validation into the Context -- easy 
to do -- and three commands must now (inside their implementation -- the 
Chain does not know anything about this) surround their current behavior 
in an "if" statement, which means that they have to know the location of 
the state information that was saved (slight increase in coupling), and 
they get processed by the Chain even if they are not relevant (very 
minor performance impact; almost never enough of a concern to worry 
about). But it would definitely work.

As Jing points out, the JavaServer Faces request processing lifecycle is 
slightly more complex, because there are more "go to the end" 
branchpoints (one after each processing phase) -- but again, either 
design pattern will work. In that case, conditional execution is 
actually easier because the relevant state (has 
FacesContext.renderResponse() been called yet?) is visible directly as 
part of the FacesContext that would be passed along anyway).

I think we're going to find that both approaches have applicability. 
You'll tend to choose the "branch" approach when the alternative 
behavior is completely different based on the branch conditions (think 
of a request processor for a SOAP request, which chooses the correct 
chain to execute based on the contents of the SOAP-Action header or 
other data in the request), while conditionals based on state will 
probably be better when the branches "merge" later on (i.e. the 
conditional stuff is in the middle of the chain, not at the end). But 
neither one of them require any change to commons-chain itself, and I'm 
going to continue to resist adding anything there until we find 
application requirements that are both (a) suitable for implementation 
as a chain in the first place; and (b) cannot be implemented cleanly 
without additional control flow type APIs.

>
> -Ted.

Craig



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


---------------------------------
Do you Yahoo!?
The New Yahoo! Shopping - with improved product search

Re: Struts-chain Behavior Discussion

Posted by "Craig R. McClanahan" <cr...@apache.org>.
Ted Husted wrote:

> Craig R. McClanahan wrote:
>
>> In terms of the chain implementation of the request processing 
>> lifecycle, this is just an unconditional command in the chain (it's 
>> implemented in o.a.s.c.servlet.PerformForward).  No skipping or 
>> stepping is requried.  See
>>
>>  contrib/struts-chain/src/conf/chain-config.xml
>>
>> for the entire definition.  You'll note that it requires no skipping 
>> -- just the conditional behavior on validation failures, which is 
>> modelled as a branch to a separately named command.
>
>
> I wonder if even these conditionals could be made part of the chain. As
> an alternative to branching, the Command could update the state of the
> Context and return false. What is now a conditional Command could be the
> next link the Chain. The "conditional" would check to see if the state
> calls for it to execute, and if so, do its business and return true.

They could indeed be made part of the chain, and "checking the current 
state to see if it's appropriate for me to do anything" is certainly 
more in the spirit of the original CoR pattern.  However, I worry a 
little that creating the need for that state information increases 
coupling between commands, and therefore increases the complexity of 
reusing commands in alternative chains.

In the real-life use case we actually have in the CVS repository (the 
one in struts-chain, which actually does work :-), the case in question 
was to deal with the fact that the Struts request processing lifecycle 
has a branch in it, based on whether or not validation succeeds.  The 
basic flow goes like this (using the class name of the command 
implementation class, and presuming we're all pretty familiar with the 
corresponding RequestProcessor behavior):

(1) LookupCommand (analogous to the processPreprocess() hook)
(2) ExceptionCatcher (no direct analog - used to implement exception 
mapping behavior)
(3) SelectLocale
(4) SelectAction
(5) CreateActionForm
(6) PopulateActionForm
(7) ValidateActionForm
(8) CreateAction
(9) ExecuteAction
(10) PerformForward

The conditional behavior happens in Step (7) -- if validation fails, an 
alternative path is desired:
(7a) SelectInput (uses the "input" attribute on the <action>)
(7b) PerformForward

At the moment, this is implemented as a branch, to a separate chain that 
the author of ValidateActionForm need not even know the name of at 
design time (it's a configuration property).  If ValidateActionForm 
detects a failure, it looks up an alternate chain in the Catalog, 
executes this chain, and then returns true (so that steps 8-10 of the 
original chain are never executed).  Note that step (10) in the original 
chain and step (7b) in the alternate chain share a single Command 
implementation instance, because Struts ends up doing the same thing 
either way (RequestDispatcher.forward() or redirect based on what 
ActionForward it is passed).  Nothing had to be coded twice.

What would this look like if we merged it into a single chain?  Probably 
something like this, with additional state-dependent checking indicated 
in [square brackets]

(1) LookupCommand
(2) ExceptionCatcher
(3) SelectLocale
(4) SelectAction
(5) CreateActionForm
(6) PopulateActionForm
(7) ValidateActionForm (must save state in the Context)
(NEW) SelectInput [skip if validation succeeded]
(8) CreateAction [skip if validation failed]
(9) ExecuteAction [skip if validation failed]
(10) PerformForward

So, implementing this as a single chain would require ValidateActionForm 
to the success/failure state of the validation into the Context -- easy 
to do -- and three commands must now (inside their implementation -- the 
Chain does not know anything about this) surround their current behavior 
in an "if" statement, which means that they have to know the location of 
the state information that was saved (slight increase in coupling), and 
they get processed by the Chain even if they are not relevant (very 
minor performance impact; almost never enough of a concern to worry 
about).  But it would definitely work.

As Jing points out, the JavaServer Faces request processing lifecycle is 
slightly more complex, because there are more "go to the end" 
branchpoints (one after each processing phase) -- but again, either 
design pattern will work.  In that case, conditional execution is 
actually easier because the relevant state (has 
FacesContext.renderResponse() been called yet?) is visible directly as 
part of the FacesContext that would be passed along anyway).

I think we're going to find that both approaches have applicability.  
You'll tend to choose the "branch" approach when the alternative 
behavior is completely different based on the branch conditions (think 
of a request processor for a SOAP request, which chooses the correct 
chain to execute based on the contents of the SOAP-Action header or 
other data in the request), while conditionals based on state will 
probably be better when the branches "merge" later on (i.e. the 
conditional stuff is in the middle of the chain, not at the end).  But 
neither one of them require any change to commons-chain itself, and I'm 
going to continue to resist adding anything there until we find 
application requirements that are both (a) suitable for implementation 
as a chain in the first place; and (b) cannot be implemented cleanly 
without additional control flow type APIs.

>
> -Ted.

Craig



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


Re: Struts-chain Behavior Discussion

Posted by Ted Husted <hu...@apache.org>.
Craig R. McClanahan wrote:
> In terms of the chain implementation of the request processing 
> lifecycle, this is just an unconditional command in the chain (it's 
> implemented in o.a.s.c.servlet.PerformForward).  No skipping or stepping 
> is requried.  See
> 
>  contrib/struts-chain/src/conf/chain-config.xml
> 
> for the entire definition.  You'll note that it requires no skipping -- 
> just the conditional behavior on validation failures, which is modelled 
> as a branch to a separately named command.

I wonder if even these conditionals could be made part of the chain. As
an alternative to branching, the Command could update the state of the
Context and return false. What is now a conditional Command could be the
next link the Chain. The "conditional" would check to see if the state
calls for it to execute, and if so, do its business and return true.

-Ted.




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


Re: Struts-chain Behavior Discussion

Posted by "Craig R. McClanahan" <cr...@apache.org>.
Jing Zhou wrote:

>It looks to me that I threw a disturbing idea. Now I change
>the subject for more discussions of different opinions.
>
>Craig mentioned the "go to" statement in programming
>languages and hinted it could be an evil if Chain implement
>the semantics of "go to" (I just called it "jump behavior").
>
>If we recognize Chain as a high level pattern regulator,
>I would not agree such a comparison is appropriate
>unless someone could convince me the following
>observations are questionable.
>
>* I studied several workflow engines (not page flow stuff, they
>  manage persisted workload for people) They all implement,
>  one way or another, the "jump behavior". I could not see
>  they violate the OO design principles as high level
>  regulators.
>  
>
You seem to be assuming that commons-chain is, or is intended to be, a 
workflow engine.  It's not.  It's fundamental plumbing that might or 
might not be used in the creation of a workflow engine, but would 
certainly not be the only API exposed to users.

>* Struts itself, as a MVC pattern regulator in its core, 
>  implements the "go to" semantics when Action returns a
>  ForwardConfig. It does a "go to" the next page, right? -:)
>
In terms of the chain implementation of the request processing 
lifecycle, this is just an unconditional command in the chain (it's 
implemented in o.a.s.c.servlet.PerformForward).  No skipping or stepping 
is requried.  See

  contrib/struts-chain/src/conf/chain-config.xml

for the entire definition.  You'll note that it requires no skipping -- 
just the conditional behavior on validation failures, which is modelled 
as a branch to a separately named command.

>In another word, IMHO, low level language principles
>may not be applicable to high level pattern/structure
>regulators. Hope people re-think it.
>
>I also recognize the facts that we do not want to overgrow
>Chain into an xml based rule engine. It should be just chain.
>But for such a simple requirement, one way is to model it
>as a "if" decision (Craig way), another way is to model it
>as a pseudo controller (Ted way). They are kind of 
>cumbersome to use. It violates the "Simple thing should
>be simple" principle - a principle that supercedes other
>programming principles. The Filter thing could offer a
>simple solution, but I haven't looked it in details yet.
>  
>
Note that even the notion of "if" is not built in to the fundamental 
chain APIs, because it doesn't belong there. It is not part of the 
fundamental pattern (which was modelled on the description from the GoF 
book).

Filter is there because one model of using a chain is to have early 
commands in the chain look up some resources (say, grab a JDBC 
connection from a connection pool), expose it in the context, and then 
return false so that the chain continues.  However, you want to make 
sure that you can return the connection to the pool when you're done, so 
the Chain you are running promises to call your postprocess() method on 
the way back out of the chain.  So, a pseudocode model of a Command to 
expose a connection might look something like this:

    public class AllocateConnection implements Filter {

        public boolean execute(Context context) throws Exception {
            DataSource ds = ... look up your DataSource via JNDI or 
whatever ...
            Connectoin conn = ds.getConnection();
            context.put("connection", connection);
            return (false); // continue the chain
        }

        public void postprocess(Context context, Exception exception) {
            Connection conn = (Connection) context.remove("connection");
            conn.close(); // Return it to the pool
        }

    }

This is a nicely encapsulated resource allocation command that can be 
reused in any application chain that needs database connections.  The 
subsequent commands that *use* the connection don't have any clue how it 
got there; they just assume that one will be made available in the 
context under an agreed-upon key.

Thus, Filter doesn't help you deal with control flow.

>The "jump behavior" requirement is very obvious in 
>Java Server Faces Specification too. When the 
>renderResponse() is called on FacesContext, the control
>is transferred to the Render Response phase after
>the current phase. This is another evidence of the
>"jump behavior" in high level pattern regulators.
>  
>
In terms of how you would implement it in a chain, its exactly the same 
as the Struts case -- no skipping or "start at this index" is required.  
Simply model the "Render Response" phase as a separately named chain, 
and execute it conditionally (just as I did in the Struts lifecycle for 
what happens on input validation failure) from each of the places where 
you can branch to Render Response.

>I would like people to open mind and think, if we
>add a method in Chain that allows us to execute
>the chain starting with a given index (currently
>the starting index is 0). Will that make the thing simple?
>Or the idea is still disturbing somewhere?
>  
>
It's not just an issue of simplicity, it's an issue of necessity.  You 
haven't yet shown me a use case where commons-chain is the right design 
pattern for implementing something, but it cannot be done (or cannot be 
done gracefully) without the "start at index" or "skip this step" 
capability.

Additionally, basing starting and/or stopping points on indexes into the 
chain is horribly fragile -- as soon as I add or remove steps elsewhere 
in the chain, I've just broken your logic, and introduced a bug in 
something I did not directly change.  That would be bad, so I'm also 
opposed to the idea on technical grounds.

Finally, even if you do have a use case that needs this capability, 
there's nothing stopping you from implementing an extended Chain that 
does it.  I contend we should not put anything like that into the 
fundamental APIs unless it's absolutely vital.

>Jing
>  
>
Craig

>Netspread Carrier
>http://www.netspread.com
>
>
>  
>



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