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" <[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]



Reply via email to