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" <[EMAIL PROTECTED]> > > To: "Struts Developers List" <[EMAIL PROTECTED]> > > 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: [EMAIL PROTECTED] > > For additional commands, e-mail: [EMAIL PROTECTED] > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [EMAIL PROTECTED] > For additional commands, e-mail: [EMAIL PROTECTED] --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]